Find significantly different loci/regions between years using shuffling to create null distributions

source("../Rscripts/BaseScripts.R")
require(data.table)
require(plyr)
require(RColorBrewer)

1 Theta null distribution

1.1 Create persite theta.pest.gz files in angsd


/home/jamcgirr/apps/angsd/misc/thetaStat  print /home/ktist/ph/data/angsd/theta/PWS91_maf00.thetas.idx | gzip > /home/ktist/ph/data/angsd/theta/PWS91_maf00_thetas.pestPG.gz

# Run printTheta.sh at farm

1.2 Run R scripts at farm to create null distribution of genome-wide thetas

Run angsd_theta_siteshuffle_null.sh at farm, which runs Pi_shuffle_pws.R - Takes long time, so create a script for each pop.year combination and run separately

Output from theta shuffling results are in Data/shuffle/theta.siteshuffle.50000.PWS91_PWS96.csv.gz

1.3 Calculate p-values for differences in theta, pi, and Tajima’s D using the results from shuffling

#from codEvol angsd_theta_siteshuffle_null_stats.R

###########################
# load functions
###########################
require(data.table)
require(plyr)
require(ggplot2)
require(RColorBrewer)


#####################
# read in and prep data
#####################

years<-c("PWS91","PWS96","PWS07","PWS17")
comb<-t(combn(years, 2))

chrmax <- fread('../Data/new_vcf/chr_sizes.bed')
chrmax<-chrmax[,-2]
colnames(chrmax)<-c("chr", "len")
chrmax$start<-c(0,cumsum(chrmax$len)[1:(nrow(chrmax)-1)])

chrmax$end<-cumsum(chrmax$len)
chrmax$middle<-(chrmax$end-chrmax$start)/2+chrmax$start

#setkey(chrmax, chr)

#Functions to calculate p-values from codEvol
calcpG <- function(thetachange, null){ # for increases in theta
  return((sum(null > thetachange)+1)/(length(null)+1)) # equation from North et al. 2002 Am J Hum Gen
}
calcpL <- function(thetachange, null){ # for decreases in theta
  return((sum(null < thetachange)+1)/(length(null)+1)) # equation from North et al. 2002 Am J Hum Gen
}


cols <- brewer.pal(4, 'Paired')[rep(1:2,13)]
Datall<-data.table()
for (p in 1: nrow(comb)){
    # max theta per genome from reshuffling (all sites) from angsd_theta_siteshuffle_null.r
    null<-fread(paste0('../Data/shuffle/theta.siteshuffle.50000.', comb[p,1],"_",comb[p,2],'.csv.gz'))
    
    #upper and lower 95%
    null[, .(tWd_l95 = quantile(mintWd, 0.05), tWd_u95 = quantile(maxtWd, probs = 0.95),
                tPd_l95 = quantile(mintPd, 0.05), tPd_u95 = quantile(maxtPd, probs = 0.95),
                tDd_l95 = quantile(mintDd, 0.05), tDd_u95 = quantile(maxtDd, probs = 0.95))]

    #assign(paste0("null.",comb[p,1],"_",comb[p,2]), null)    
    
    # sliding windows theta change (GATK sites) from angsd_theta_siteshuffle_null.r
    dat<-fread(paste0('../Data/shuffle/theta_change_region_50000.', comb[p,1],"_",comb[p,2],'.csv.gz'), drop = 1)
    dat[,pop:=paste0(comb[p,1],"_",comb[p,2])]
    
    dat<-merge(dat, chrmax[,c("chr","start")], by.x="Chromo", by.y = "chr")
    dat[, POSgen := WinCenter + start]
    dat[,start := NULL] #remove start
    
    #calculate p-values
    #1. thetaW loci
    dat[tWd > 0, tWd.p := calcpG(tWd, null$maxtWd), by = .(Chromo, WinCenter)] # thetaW  loci
    dat[tWd <= 0, tWd.p := calcpL(tWd, null$mintWd), by = .(Chromo, WinCenter)]
    #2. theta pi
    dat[tPd > 0, tPd.p := calcpG(tPd, null$maxtPd), by = .(Chromo, WinCenter)] # theta pi
    dat[tPd <= 0, tPd.p := calcpL(tPd, null$mintPd), by = .(Chromo, WinCenter)]
    
    #Tajima's D
    dat[tDd > 0, tDd.p := calcpG(tDd, null$maxtDd), by = .(Chromo, WinCenter)] # tajima's D
    dat[tDd <= 0, tDd.p := calcpL(tDd, null$mintDd), by = .(Chromo, WinCenter)]

    write.csv(dat, file=gzfile(paste0('../Output/Pi/Shuffle/theta_siteshuffle_', comb[p,1],"_",comb[p,2],'.csv.gz')))
    
    Datall<-rbind(Datall, dat)
}

write.csv(Datall, file=gzfile(paste0('../Output/Pi/Shuffle/theta_siteshuffle_PWS_summary.csv.gz')))

1.4 Plot the results

1.4.1 Changes in Pi/Theta/D between years

## Plot the results ##
Datall<-fread('../Output/Pi/Shuffle/theta_siteshuffle_PWS_summary.csv.gz')

winsz = 5e4 

#Changes in Pi between years
Datall$Chromo<-factor(Datall$Chromo, levels=c(paste0("chr",1:26)))
Datall$pop<-factor(Datall$pop, levels=c("PWS91_PWS96","PWS91_PWS07","PWS91_PWS17","PWS96_PWS07","PWS96_PWS17","PWS07_PWS17"))

ggplot(Datall, aes(POSgen, tPd/winsz, color = Chromo)) + 
    geom_point(size = 0.5, alpha = 0.3) +
    facet_wrap(~pop, ncol = 1) +
    scale_color_manual(values = cols, guide="none") +
    ylab('Change in pi per site')+xlab("Chromosome")+
    ggtitle("Changes in Pi")+
    scale_x_continuous(breaks=chrmax$middle, labels=1:26)+
    theme_bw()
ggsave(paste0('../Output/Pi/Shuffle/Changes_in_Pi_PWS.png'), width = 7.5, height = 9, dpi = 300)

# plot theta_Watterson change
ggplot(Datall, aes(POSgen, tWd/winsz, color = Chromo)) + 
  geom_point(size = 0.5, alpha = 0.3) +
  scale_color_manual(values = cols, guide="none") +
    facet_wrap(~pop, ncol = 1) +
  ylab('Change in Wattersons theta per site')+xlab("Chromosome")+
  ggtitle("Changes in Pi")+
    scale_x_continuous(breaks=chrmax$middle, labels=1:26)+
    theme_bw()
ggsave('../Output/Pi/Shuffle/Changes_in_thetaW_PWS.png', width = 7.5, height = 9, dpi = 300)

# plot Tajima's D change
ggplot(Datall, aes(POSgen, tDd, color = Chromo)) + 
    geom_point(size = 0.5, alpha = 0.3) +
    scale_color_manual(values = cols,guide="none") +
    facet_wrap(~pop, ncol = 1) +
    ylab('Change in Tajimas D per window')+xlab("Chromosome")+
    ggtitle("Changes in Tajima's D")+
    scale_x_continuous(breaks=chrmax$middle, labels=1:26)+
    theme_bw()
ggsave('../Output/Pi/Shuffle/Changes_in_TajimasD_PWS.png', width = 7.5, height = 9, dpi = 300)

1.4.2 Plot the p-values for differences in P/Theta along the genome

# plot pi p-value vs. position 
cols <- brewer.pal(4, 'Paired')[rep(1:2,13)]
Datall$Chromo<-factor(Datall$Chromo, levels=c(paste0("chr",1:26)))
Datall$pop<-factor(Datall$pop, levels=c("PWS91_PWS96","PWS91_PWS07","PWS91_PWS17","PWS96_PWS07","PWS96_PWS17","PWS07_PWS17"))

ggplot(Datall, aes(POSgen, -log10(tPd.p)*sign(tPd), color = Chromo)) + 
    geom_point(size = 0.4, alpha = 0.3) +
    facet_wrap(~pop, ncol = 1) +
    scale_color_manual(values = cols, guide="none") +xlab("Chromosome")+
    ylab("log10(P-value)")+
    geom_hline(yintercept = log10(0.05), linetype = 'dashed', color = 'red',size=0.3) +
    geom_hline(yintercept = -log10(0.05), linetype = 'dashed', color = 'red', size=0.3)+
    ggtitle("P-values for changes in Pi")+
    scale_x_continuous(breaks=chrmax$middle, labels=1:26)+
    theme_bw()
ggsave('../Output/Pi/Shuffle/Changes_in_Pi.siteshuffle.p-values_PWS.png', width = 7.5, height =11, units = 'in', dpi = 300)


# plot thetaW p-value vs. position (all loci)
ggplot(Datall, aes(POSgen, -log10(tWd.p)*sign(tWd), color = Chromo)) + 
  geom_point(size = 0.4, alpha = 0.3) +
  facet_wrap(~pop, ncol = 1) +
  scale_color_manual(values = cols, guide="none") +xlab("Chromosome")+
    ylab("log10(P-value)")+
  geom_hline(yintercept = log10(0.05), linetype = 'dashed', color = 'red', size=0.3) +
  geom_hline(yintercept = -log10(0.05), linetype = 'dashed', color = 'red', size=0.3)+
      ggtitle("P-values for changes in Theta")+
    scale_x_continuous(breaks=chrmax$middle, labels=1:26)+
    theme_bw()
ggsave('../Output/Pi/Shuffle/Changes_in_thetaW.siteshuffle.p-values_PWS.png', width = 7.5, height =11, units = 'in', dpi = 300)

#plot Tajama's D p-value vs. position
ggplot(Datall, aes(POSgen, -log10(tDd.p)*sign(tDd), color = Chromo)) + 
    geom_point(size = 0.4, alpha = 0.3) +
    facet_wrap(~pop, ncol = 1) +
    scale_color_manual(values = cols, guide="none") +xlab("Chromosome")+
    ylab("log10(P-value)")+
    geom_hline(yintercept = log10(0.05), linetype = 'dashed',  color = 'red', size=0.3) +
    geom_hline(yintercept = -log10(0.05), linetype = 'dashed', color = 'red', size=0.3)+
    ggtitle("P-values for changes in Tajima's D")+
    scale_x_continuous(breaks=chrmax$middle, labels=1:26)+
    theme_bw()
ggsave('../Output/Pi/Shuffle/Changes_in_TajimaD.siteshuffle.p-values_PWS.png', width = 7.5, height =11, units = 'in', dpi = 300)

1.5 Find the regions with signfiicant P-values (Outlier regions)

1.5.1 Pi

# Outliers

Pi_outliers<-Datall[tPd.p < 0.05,]
Theta_outliers<-Datall[tWd.p < 0.05,]
TajimaD_outliers<-Datall[tDd.p < 0.05,] #no outliers

# Summary per chromosome per population
pi<-data.frame(table(Pi_outliers$pop, Pi_outliers$Chromo))
the<-data.frame(table(Theta_outliers$pop, Theta_outliers$Chromo))
D<-data.frame(table(TajimaD_outliers$pop, TajimaD_outliers$Chromo))

# Summary per population
pi2<-data.frame(table(Pi_outliers$pop))
the2<-data.frame(table(Theta_outliers$pop))
Ds2<-data.frame(table(TajimaD_outliers$pop))


#plot PWS91-96, 96-07, and 07-17
yrs<-c("PWS91_PWS96","PWS96_PWS07","PWS07_PWS17")
col3<-brewer.pal(5,"PuRd")[c(2,3,5)]
div1<-diverging_hcl(6, palette="Blue-Red")
#reverse the color
div2<-rev(div1)

pis<-pi[pi$Var1 %in% yrs,]
pis$Var1<-factor(pis$Var1, levels=yrs)
ggplot(pis, aes(x=Var2, y=Freq, fill=Var1))+
    geom_bar(stat="identity",position=position_dodge(width=0.8))+
    scale_fill_manual(values=col3)+
    theme_classic()+
    theme(axis.text.x = element_text(angle=45, hjust=1), legend.title = element_blank())+
    ggtitle(expression(paste("Changes in ", pi)))+
    xlab('')+ylab('Number of regions with P<0.05')
ggsave("../Output/Pi/Shuffle/Pi_significant_perChrom_perPop.png", width = 8, height = 4, dpi=300) 

# Per population comparison
ggplot(pi2, aes(x=Var1, y=Freq, fill=Var1))+
    geom_bar(stat="identity",position=position_dodge(width=0.8))+
    scale_fill_manual(values=div1)+
    theme_classic()+
    theme(axis.text.x = element_text(angle=45, hjust=1), legend.title = element_blank())+
    ggtitle(expression(paste("Changes in ", pi)))+
    xlab('')+ylab('Number of regions with P<0.05')
ggsave("../Output/Pi/Shuffle/Pi_significant_perComparison.png", width = 5, height = 4, dpi=300) 

#ordered
pi3<-pi2[order(pi2$Freq, decreasing = T),]
pi3$Var1<-factor(pi3$Var1, levels=paste0(unique(pi3$Var1)))
ggplot(pi3, aes(x=Var1, y=Freq, fill=Var1))+
    geom_bar(stat="identity",position=position_dodge(width=0.8))+
    scale_fill_manual(values=div2)+
    theme_classic()+
    theme(axis.text.x = element_text(angle=45, hjust=1), legend.title = element_blank())+
    ggtitle(expression(paste("Changes in ", pi)))+
    xlab('')+ylab('Number of regions with P<0.05')
ggsave("../Output/Pi/Shuffle/Pi_significant_perComparison_ordered.png", width = 5, height = 4, dpi=300) 

#Assign colors to the comparison group
names(div2)<- unique(pi3$Var1)

1.5.2 Theta

#Thetea
ths<-the[the$Var1 %in% yrs,]
ths$Var1<-factor(ths$Var1, levels=yrs)
ggplot(ths, aes(x=Var2, y=Freq, fill=Var1))+
    geom_bar(stat="identity",position=position_dodge(width=0.8))+
    scale_fill_manual(values=col3)+
    theme_classic()+
    theme(axis.text.x = element_text(angle=45, hjust=1), legend.title = element_blank())+
    ggtitle(paste0("Changes in theta"))+
    xlab('')+ylab('Number of regions with P<0.05')
ggsave("../Output/Pi/Shuffle/Theta_significant_perChrom_perPop.png", width = 5, height = 3, dpi=300) 

ggplot(the2, aes(x=Var1, y=Freq, fill=Var1))+
    geom_bar(stat="identity",position=position_dodge(width=0.8))+
    scale_fill_manual(values=div1)+
    theme_classic()+
    theme(axis.text.x = element_text(angle=45, hjust=1), legend.title = element_blank())+
    ggtitle(paste("Changes in theta"))+
    xlab('')+ylab('Number of regions with P<0.05')
ggsave("../Output/Pi/Shuffle/Theta_significant_perComparison.png", width = 5, height = 4, dpi=300) 


the3<-the2[order(the2$Freq, decreasing = T),]
the3$Var1<-factor(the3$Var1, levels=paste0(unique(the3$Var1)))

ggplot(the3, aes(x=Var1, y=Freq, fill=Var1))+
    geom_bar(stat="identity",position=position_dodge(width=0.8))+
    scale_fill_manual(name = "Var1",values = div2)+
    theme_classic()+
    theme(axis.text.x = element_text(angle=45, hjust=1), legend.title = element_blank())+
    ggtitle(paste("Changes in theta"))+
    xlab('')+ylab('Number of regions with P<0.05')
ggsave("../Output/Pi/Shuffle/Theta_significant_perComparison_ordered.png", width = 5, height = 4, dpi=300) 

1.5.3 Tajima’s D - No regions with P < 0.05

# Tajima's D
ggplot(Ds2, aes(x=Var1, y=Freq, fill=Var1))+
    geom_bar(stat="identity",position=position_dodge(width=0.8))+
    scale_fill_manual(values=div1)+
    theme_classic()+
    theme(axis.text.x = element_text(angle=45, hjust=1), legend.title = element_blank())+
    ggtitle(paste0("Changes in Tajima's D"))+
    xlab('')+ylab('Number of regions with P<0.05')
ggsave("../Output/Pi/Shuffle/TajimaD_significant_perComparison.png", width = 5, height = 4, dpi=300) 


D2<-D[D$Var1 %in% yrs,]
D2$Var1<-factor(D2$Var1, levels=yrs)
ggplot(D2, aes(x=Var2, y=Freq, fill=Var1))+
    geom_bar(stat="identity",position=position_dodge(width=0.8))+
    scale_fill_manual(values=col3)+
    theme_classic()+
    theme(axis.text.x = element_text(angle=45, hjust=1), legend.title = element_blank())+
     ggtitle(paste0("Changes in Tajima's D"))+
    xlab('')+ylab('Number of regions with P>0.05')
#ggsave("../Output/Pi/Shuffle/TajimaD_significant_perChrom_perPop.png", width = 8, height = 4, dpi=300) 
  • Most differences exist between 1996 and 2007
  • Chr25 has the most significant regions for changes in Pi and Theta



2 Fst genome-scan using a null model

  • from Pinsky et al. 2021 https://github.com/pinskylab/codEvol
  • Create a null distribution of expected maximum Fst
  • Define a genome-wide p-value for each region as (r+1)/(n+1), where r was the number of null simulations with maximum change greater than or equal to the empirical value and n was the number of shuffles

2.1 Shuffle Fst and create a null model of max Fst

  • Based on angsd persite Fst output
  1. After running angsd (realSFS), print a persite Fst file
#run FstPWSprint.sh

/home/jamcgirr/apps/angsd/misc/realSFS fst print  /home/ktist/ph/data/angsd/analysis/fst_PWS91_PWS07_persite_maf00.fst.idx > /home/ktist/ph/data/angsd/analysis/fst_PWS91_PWS07_persite_maf00.txt
bgzip /home/ktist/ph/data/angsd/analysis/fst_PWS91_PWS07_persite_maf00.txt
  1. Run Fst_shuffle_pws.R at Farm (slurm script: angsd_fst_siteshuffle_null.sh)
# From https://github.com/pinskylab/codEvol angsd_fst_siteshuffle_null.r

# shuffle ANGSD persite FST A and B values across sites and calculate windowed FST to get a null distribution of max genome-wide FST
# need fst persite output from angsd fst_*_persite_maf00.txt.gz files

# to run on farm


##### R code  ####### 

# parameters
winsz <- 50000 # window size
winstp <- 10000 # window step
nrep <- 1000 # number of reshuffles
minloci <- 10 # minimum number of loci per window to consider


# load functions
require(data.table)


#############
# Prep data
#############
# load fst A/B data
#can <- fread('analysis/Can_40.Can_14.fst.AB.gz')
#setnames(can, c('CHROM', 'POS', 'A', 'B'))

pws9196 <- fread('/home/ktist/ph/data/angsd/analysis/fst_PWS91_PWS96_persite_maf00.txt.gz')
setnames(pws9196, c('CHROM', 'POS', 'A', 'B'))
pws9107 <- fread('/home/ktist/ph/data/angsd/analysis/fst_PWS91_PWS07_persite_maf00.txt.gz')
setnames(pws9107, c('CHROM', 'POS', 'A', 'B'))
pws9117 <- fread('/home/ktist/ph/data/angsd/analysis/fst_PWS91_PWS17_persite_maf00.txt.gz')
setnames(pws9117, c('CHROM', 'POS', 'A', 'B'))
pws9607 <- fread('/home/ktist/ph/data/angsd/analysis/fst_PWS96_PWS07_persite_maf00.txt.gz')
setnames(pws9607, c('CHROM', 'POS', 'A', 'B'))
pws9617 <- fread('/home/ktist/ph/data/angsd/analysis/fst_PWS96_PWS17_persite_maf00.txt.gz')
setnames(pws9617, c('CHROM', 'POS', 'A', 'B'))
pws0717 <- fread('/home/ktist/ph/data/angsd/analysis/fst_PWS07_PWS17_persite_maf00.txt.gz')
setnames(pws0717, c('CHROM', 'POS', 'A', 'B'))

PWS<-list()
PWS[[1]]<-pws9196
PWS[[2]]<-pws9107
PWS[[3]]<-pws9117
PWS[[4]]<-pws9607
PWS[[5]]<-pws9617 
PWS[[6]]<-pws0717 
    
 
# create new columns as indices for windows

for (i in 1: length(PWS)){
    df<-PWS[[i]]
    for(j in 1:(winsz/winstp)){
        df[, (paste0('win', j)) := floor((POS - (j-1)*winstp)/winsz)*winsz + winsz/2 + (j-1)*winstp]
    }
    PWS[[i]]<-df
}

# mark windows with < minloci for removal
rem <- rep(0, 6) # number of windows removed for each of the 6 comparisons

for(i in 1: length(PWS)){
    pw<-PWS[[i]]
    for(j in 1:(winsz/winstp)){
        pwwin <- pw[, .(nsnps = length(POS)), by = .(win = get(paste0('win', j)))] # calc num snps per window
        rem[1] <- rem[1] + pwwin[, sum(nsnps < minloci)] # record number to be removed
        pwwin[, (paste0('win', j, 'keep')) := 1] # create col to mark which windows to keep
        pwwin[nsnps < minloci, (paste0('win', j, 'keep')) := 0] # mark windows to remove
        pwwin[, nsnps := NULL] # drop column
        setnames(pwwin, "win", paste0('win', j)) # change col name
        pw <- merge(pw, pwwin, by = paste0('win', j), all.x = TRUE) # merge keeper col back to full dataset
    }
    PWS[[i]]<-pw
}

rem # number of windows removed for each comparison




####################################
# shuffle and recalc windowed FST
####################################
colnms <- c('CHROM', 'POS', paste0('win', 1:(winsz/winstp)), paste0('win', 1:(winsz/winstp), 'keep')) # list of column names we want out of the base data.table

# PWS07-17
pops<-c("PWS91.96","PWS91.07","PWS91.17","PWS96.07","PWS96.17","PWS07.17")


for(p in 1:length(PWS)){
    print(paste0('Starting ', pops[p]))

    pw<-PWS[[p]]
    for(i in 1:nrep){
        cat(i); cat(' ')
        # create new dataset
        inds <- sample(1:nrow(pw), nrow(pw), replace = FALSE)
        temp <- cbind(pw[, ..colnms], pw[inds, .(A, B)]) # shuffle FSTs across positions
        
        # calc fst for each window to keep
        for(j in 1:(winsz/winstp)){
            temp2 <- temp[get(paste0('win', j, 'keep')) == 1, ] # trim to windows to keep. can't combine with next line for some reason.
            if(j ==1) tempfsts <- temp2[, .(fst = sum(A)/sum(B)), by = .(CHROM, POS = get(paste0('win', j)))]
            if(j > 1) tempfsts <- rbind(tempfsts, temp2[, .(fst = sum(A)/sum(B)), by = .(CHROM, POS = get(paste0('win', j)))])
        }
        
        # save the max windowed fst
        # exclude windows with negative midpoints
        if(i == 1) maxfst <- tempfsts[POS > 0, max(fst, na.rm = TRUE)]  
        if(i > 1) maxfst <- c(maxfst, tempfsts[POS > 0, max(fst, na.rm = TRUE)])
    }

    print(paste('Max:', max(maxfst, na.rm = TRUE), '; 95th:', quantile(maxfst, prob = 0.95, na.rm = TRUE)))
    
    write.csv(maxfst, gzfile(paste0('/home/ktist/ph/data/angsd/analysis/',pops[p], '_siteshuuffle.csv.gz')), row.names = FALSE)
    rm(maxfst)
}

2.2 Assess the results from site reshuffled Fst

Need - sitehuffle results fst_siteshuuffle.csv.gz - window-based Fst results from angsd _50kWindow_maf00 - persite Fst files after LD pruning (with AB info) *_persite_maf00_ldtrim.csv.gz

#from https://github.com/pinskylab/codEvol

# parameters
minloci <- 10 
winsz <- 50000 # window size
winstp <- 10000 # window step

# load functions
require(data.table)
require(ggplot2)

calcp <- function(fst, null) return((sum(null > fst)+1)/(length(null)+1)) # equation from North et al. 2002 Am J Hum Gen

# read in and prep data
years<-c("PWS91","PWS96","PWS07","PWS17")
comb<-t(combn(years, 2))

# continuous nucleotide position for the whole genome
chrmax <- fread('../Data/new_vcf/chr_sizes.bed')
chrmax<-chrmax[,-2]
colnames(chrmax)<-c("chr", "len")
chrmax$start<-c(0,cumsum(chrmax$len)[1:(nrow(chrmax)-1)])
setkey(chrmax, chr)

prunedFst_gw<-data.frame(pop1=comb[,1],pop2=comb[,2])
#for (p in 1: nrow(comb)){
    for (p in 1:5){
    #genome-wide max Fst from reshuffling (unlinked sites)
    null<-fread(paste0('Data/shuffle/', comb[p,1],".",comb[p,2],'_fst_siteshuuffle.csv.gz'))
    #window-based Fst from angsd            
    fstwin <- fread(paste0('Data/new_vcf/angsd/fromVCF/2D/fst_',comb[p,1],"_",comb[p,2],'_50kWindow_maf00'), header = FALSE, col.names = c('region', 'chr', 'midPos', 'Nsites', 'fst')) # all sites
    #persite fst (AB) -pruned sites
    AB <- fread(paste0('Data/shuffle/fst_',comb[p,1],"_",comb[p,2],'_persite_maf00_ldtrim.csv.gz'))
    
    # merge nucleotide position into the frequency files
    setkey(AB, CHROM)
    AB <- AB[chrmax[, .(CHROM = chr, start)], ]
    AB[, posgen := POS + start]
    AB[,start := NULL]
    
    # Calc genome-wide FST
    prunedFst_gw$gwFst[p]<-AB[!is.na(A), sum(A)/sum(B)]
    
    # Calc windowed FST
    # create new columns as indices for windows
    for(j in 1:(winsz/winstp)){
        AB[, (paste0('win', j)) := floor((POS - (j-1)*winstp)/winsz)*winsz + winsz/2 + (j-1)*winstp]
    }
    
    # calc fst and # snps per window
    for(j in 1:(winsz/winstp)){
        if(j ==1){
            fstwin <- AB[, .(fst = sum(A)/sum(B), nloci = length(POS)), by = .(CHROM, midPos = get(paste0('win', j)))]
        } 
        if(j > 1){
            fstwin <- rbind(fstwin, AB[, .(fst = sum(A)/sum(B), nloci = length(POS)), by = .(CHROM, midPos = get(paste0('win', j)))])
        } 
    }
    
    ## null model stats
    fstats<-null[, .(max = max(x), u95 = quantile(x, probs = 0.95))]
    prunedFst_gw$null.Fstmax[p]<-fstats$max[1]
    prunedFst_gw$null.Fst.95q[p]<-fstats$u95[1]
    
    #Calculate p-values
    pval<-fstwin[, p := calcp(fst, null$x), by = .(CHROM, midPos)]
    
    #combined the datasets
    pair<-paste0(comb[p,1],"_",comb[p,2])
    fstwin[, pop := pair ]
    write.csv(fstwin, paste0("../Output/Fst/fst_siteshuffle.pairwise_", pair,".csv"))
}

write.csv(prunedFst_gw, "../Output/Fst/fst_siteshuffle_pws_summary.csv")

data<-data.frame()
for(i in 1: nrow(comb)){
    pair<-paste0(comb[i,1],"_",comb[i,2])
    df<-fread(paste0("../Output/Fst/fst_siteshuffle.pairwise_", pair,".csv"))
    df<-df[!is.na(fst) & midPos > 0, ]
    df[,ch:= as.integer(gsub("chr",'', CHROM))]
    setkey(df,CHROM)
    df<-df[chrmax[, .(CHROM = chr, start)], ]
    df[,pos.gw:= midPos+start]
    #setkey(df, ch, midPos)
    data<-rbind(data, df)
}

write.csv(data, file = gzfile('../Output/Fst/fst_siteshuffle.angsd.PWS.csv.gz'), row.names = FALSE)

2.3 Plot the results

data<-fread('../Output/Fst/fst_siteshuffle.angsd.PWS.csv.gz')

#pop as factor 
data[, pop := factor(pop, levels = c("PWS91_PWS96","PWS91_PWS07","PWS91_PWS17","PWS96_PWS07","PWS96_PWS17","PWS07_PWS17"))]

# plot p-value vs. position
two_cols<-rep(c("steelblue","lightblue"), times=13)
minloci <- 10 # minimum number of loci per window to consider

ggplot(data[nloci >= minloci, ], aes(pos.gw, -log10(p), color = factor(ch))) + 
    geom_point(size = 0.2, alpha = 0.5) +
    facet_wrap(~pop, ncol = 1) +
    scale_color_manual(values = two_cols, guide='none') +
    geom_hline(yintercept = -log10(0.05), linetype = 'dashed', color = 'grey')+
    theme_bw()+
    theme(axis.text.x = element_blank())+
    xlab("Genome")
ggsave("../Output/Fst/fst.siteshuffle.p_vs_pos.PWS.png", width = 7.5, height = 7.5,dpi = 300)

  • Number of loci per window vs. Fst p-values
# plot p-value vs. nloci to check if any biases exist
ggplot(data, aes(nloci, -log10(p), color = pop)) + 
    geom_point(size = 0.6, alpha = 0.5) +
    geom_hline(yintercept = -log10(0.05), linetype = 'dashed', color = 'grey') + 
    scale_x_log10()+theme_bw()+theme(legend.title = element_blank())+
    guides(color = guide_legend(override.aes = list(size = 3, alpha=1)))
ggsave("../Output/Fst/fst.siteshuffle.p_vs_nloci.PWS.png", width = 8, height =4,dpi = 300)

2.4 Significant outlier regions

2.4.1 p-value < 0.05

outliers<-data[p < 0.05, ]
write.csv(outliers, "../Output/Fst/Fst_nullshuffling_outliers_PWS.csv")

counts<-data.table(table(outliers$pop))
ggplot(counts, aes(x=V1, y=N))+
    geom_bar(stat="identity", fill=cols[4])+
    xlab('')+ylab('')+
    theme_classic()+
    theme(axis.text.x = element_text(angle=45, hjust=1))
ggsave("../Output/Fst/Fst_outliers_byComparison.png", width = 4, height = 3, dpi=300 )


counts$V1<-factor(counts$V1, levels=c("PWS96_PWS07","PWS07_PWS17","PWS91_PWS96", "PWS91_PWS07", "PWS91_PWS17","PWS96_PWS17"))
ggplot(counts, aes(x=V1, y=N, fill=V1))+
    geom_bar(stat="identity")+
    scale_fill_manual(name = "V",values = div2)+
    xlab('')+ylab('Number of regions with P<0.05')+
    theme_classic()+ggtitle("Fst (shuffle)")+
    theme(axis.text.x = element_text(angle=45, hjust=1), legend.title = element_blank())
ggsave("../Output/Fst/Fst_outliers_byComparison_ordered.png", width = 4, height = 3, dpi=300 )



#outliers<-read.csv("../Output/Fst/Fst_nullshuffling_outliers_PWS.csv", row.names = 1)
knitr::kable(outliers[,c(2,3,4,5,6,7,8)], caption="Outlier regions")

#Outlier regions
#CHROM  midPos  fst nloci   p   pop ch
#chr25  825000  0.1210997   138 0.003996    PWS96_PWS07 25
#chr25  835000  0.0818802   279 0.020979    PWS96_PWS07 25
#chr25  845000  0.0721926   311 0.033966    PWS96_PWS07 25
#chr25  805000  0.1242652   166 0.002997    PWS96_PWS07 25
#chr25  815000  0.1377218   155 0.002997    PWS96_PWS07 25
#chr19  1375000 0.1251602   42  0.003996    PWS07_PWS17 19

2.4.2 Top 1% outliers & P< 0.2

  • relaxing the cutoff


* NO overlapping regions from PCAngsd selection scan

LS0tCnRpdGxlOiAiU2h1ZmZsaW5nIFBpL0ZzdC9UaGV0YS9EIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgICAgdG9jOiB0cnVlIAogICAgICB0b2NfZmxvYXQ6IHRydWUKICAgICAgbnVtYmVyX3NlY3Rpb25zOiBUcnVlCiAgICAgIHRoZW1lOiBsdW1lbgogICAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgICBkZl9wcmludDogcGFnZWQKLS0tCgojIEZpbmQgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQgbG9jaS9yZWdpb25zIGJldHdlZW4geWVhcnMgdXNpbmcgc2h1ZmZsaW5nIHRvIGNyZWF0ZSBudWxsIGRpc3RyaWJ1dGlvbnN7LnVubnVtYmVyZWR9ICAKIApgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpzb3VyY2UoIi4uL1JzY3JpcHRzL0Jhc2VTY3JpcHRzLlIiKQpyZXF1aXJlKGRhdGEudGFibGUpCnJlcXVpcmUocGx5cikKcmVxdWlyZShSQ29sb3JCcmV3ZXIpCmBgYAoKCiMgVGhldGEgbnVsbCBkaXN0cmlidXRpb24KCiMjIENyZWF0ZSBwZXJzaXRlIHRoZXRhLnBlc3QuZ3ogZmlsZXMgaW4gYW5nc2QKCmBgYHtiYXNofQoKL2hvbWUvamFtY2dpcnIvYXBwcy9hbmdzZC9taXNjL3RoZXRhU3RhdCAgcHJpbnQgL2hvbWUva3Rpc3QvcGgvZGF0YS9hbmdzZC90aGV0YS9QV1M5MV9tYWYwMC50aGV0YXMuaWR4IHwgZ3ppcCA+IC9ob21lL2t0aXN0L3BoL2RhdGEvYW5nc2QvdGhldGEvUFdTOTFfbWFmMDBfdGhldGFzLnBlc3RQRy5negoKIyBSdW4gcHJpbnRUaGV0YS5zaCBhdCBmYXJtCmBgYAoKCiMjIFJ1biBSIHNjcmlwdHMgYXQgZmFybSB0byBjcmVhdGUgbnVsbCBkaXN0cmlidXRpb24gb2YgZ2Vub21lLXdpZGUgdGhldGFzCgpSdW4gYW5nc2RfdGhldGFfc2l0ZXNodWZmbGVfbnVsbC5zaCBhdCBmYXJtLCB3aGljaCBydW5zIFBpX3NodWZmbGVfcHdzLlIgCiAtIFRha2VzIGxvbmcgdGltZSwgc28gY3JlYXRlIGEgc2NyaXB0IGZvciBlYWNoIHBvcC55ZWFyIGNvbWJpbmF0aW9uIGFuZCBydW4gc2VwYXJhdGVseSAKCk91dHB1dCBmcm9tIHRoZXRhIHNodWZmbGluZyByZXN1bHRzIGFyZSBpbiBEYXRhL3NodWZmbGUvdGhldGEuc2l0ZXNodWZmbGUuNTAwMDAuUFdTOTFfUFdTOTYuY3N2Lmd6CgoKIyMgQ2FsY3VsYXRlIHAtdmFsdWVzIGZvciBkaWZmZXJlbmNlcyBpbiB0aGV0YSwgcGksIGFuZCBUYWppbWEncyBEIHVzaW5nIHRoZSByZXN1bHRzIGZyb20gc2h1ZmZsaW5nIAoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KI2Zyb20gY29kRXZvbCBhbmdzZF90aGV0YV9zaXRlc2h1ZmZsZV9udWxsX3N0YXRzLlIKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIGxvYWQgZnVuY3Rpb25zCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpyZXF1aXJlKGRhdGEudGFibGUpCnJlcXVpcmUocGx5cikKcmVxdWlyZShnZ3Bsb3QyKQpyZXF1aXJlKFJDb2xvckJyZXdlcikKCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyByZWFkIGluIGFuZCBwcmVwIGRhdGEKIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgp5ZWFyczwtYygiUFdTOTEiLCJQV1M5NiIsIlBXUzA3IiwiUFdTMTciKQpjb21iPC10KGNvbWJuKHllYXJzLCAyKSkKCmNocm1heCA8LSBmcmVhZCgnLi4vRGF0YS9uZXdfdmNmL2Nocl9zaXplcy5iZWQnKQpjaHJtYXg8LWNocm1heFssLTJdCmNvbG5hbWVzKGNocm1heCk8LWMoImNociIsICJsZW4iKQpjaHJtYXgkc3RhcnQ8LWMoMCxjdW1zdW0oY2hybWF4JGxlbilbMToobnJvdyhjaHJtYXgpLTEpXSkKCmNocm1heCRlbmQ8LWN1bXN1bShjaHJtYXgkbGVuKQpjaHJtYXgkbWlkZGxlPC0oY2hybWF4JGVuZC1jaHJtYXgkc3RhcnQpLzIrY2hybWF4JHN0YXJ0Cgojc2V0a2V5KGNocm1heCwgY2hyKQoKI0Z1bmN0aW9ucyB0byBjYWxjdWxhdGUgcC12YWx1ZXMgZnJvbSBjb2RFdm9sCmNhbGNwRyA8LSBmdW5jdGlvbih0aGV0YWNoYW5nZSwgbnVsbCl7ICMgZm9yIGluY3JlYXNlcyBpbiB0aGV0YQogIHJldHVybigoc3VtKG51bGwgPiB0aGV0YWNoYW5nZSkrMSkvKGxlbmd0aChudWxsKSsxKSkgIyBlcXVhdGlvbiBmcm9tIE5vcnRoIGV0IGFsLiAyMDAyIEFtIEogSHVtIEdlbgp9CmNhbGNwTCA8LSBmdW5jdGlvbih0aGV0YWNoYW5nZSwgbnVsbCl7ICMgZm9yIGRlY3JlYXNlcyBpbiB0aGV0YQogIHJldHVybigoc3VtKG51bGwgPCB0aGV0YWNoYW5nZSkrMSkvKGxlbmd0aChudWxsKSsxKSkgIyBlcXVhdGlvbiBmcm9tIE5vcnRoIGV0IGFsLiAyMDAyIEFtIEogSHVtIEdlbgp9CgoKY29scyA8LSBicmV3ZXIucGFsKDQsICdQYWlyZWQnKVtyZXAoMToyLDEzKV0KRGF0YWxsPC1kYXRhLnRhYmxlKCkKZm9yIChwIGluIDE6IG5yb3coY29tYikpewogICAgIyBtYXggdGhldGEgcGVyIGdlbm9tZSBmcm9tIHJlc2h1ZmZsaW5nIChhbGwgc2l0ZXMpIGZyb20gYW5nc2RfdGhldGFfc2l0ZXNodWZmbGVfbnVsbC5yCiAgICBudWxsPC1mcmVhZChwYXN0ZTAoJy4uL0RhdGEvc2h1ZmZsZS90aGV0YS5zaXRlc2h1ZmZsZS41MDAwMC4nLCBjb21iW3AsMV0sIl8iLGNvbWJbcCwyXSwnLmNzdi5neicpKQogICAgCiAgICAjdXBwZXIgYW5kIGxvd2VyIDk1JQogICAgbnVsbFssIC4odFdkX2w5NSA9IHF1YW50aWxlKG1pbnRXZCwgMC4wNSksIHRXZF91OTUgPSBxdWFudGlsZShtYXh0V2QsIHByb2JzID0gMC45NSksCiAgICAgICAgICAgICAgICB0UGRfbDk1ID0gcXVhbnRpbGUobWludFBkLCAwLjA1KSwgdFBkX3U5NSA9IHF1YW50aWxlKG1heHRQZCwgcHJvYnMgPSAwLjk1KSwKICAgICAgICAgICAgICAgIHREZF9sOTUgPSBxdWFudGlsZShtaW50RGQsIDAuMDUpLCB0RGRfdTk1ID0gcXVhbnRpbGUobWF4dERkLCBwcm9icyA9IDAuOTUpKV0KCiAgICAjYXNzaWduKHBhc3RlMCgibnVsbC4iLGNvbWJbcCwxXSwiXyIsY29tYltwLDJdKSwgbnVsbCkgICAgCiAgICAKICAgICMgc2xpZGluZyB3aW5kb3dzIHRoZXRhIGNoYW5nZSAoR0FUSyBzaXRlcykgZnJvbSBhbmdzZF90aGV0YV9zaXRlc2h1ZmZsZV9udWxsLnIKICAgIGRhdDwtZnJlYWQocGFzdGUwKCcuLi9EYXRhL3NodWZmbGUvdGhldGFfY2hhbmdlX3JlZ2lvbl81MDAwMC4nLCBjb21iW3AsMV0sIl8iLGNvbWJbcCwyXSwnLmNzdi5neicpLCBkcm9wID0gMSkKICAgIGRhdFsscG9wOj1wYXN0ZTAoY29tYltwLDFdLCJfIixjb21iW3AsMl0pXQogICAgCiAgICBkYXQ8LW1lcmdlKGRhdCwgY2hybWF4WyxjKCJjaHIiLCJzdGFydCIpXSwgYnkueD0iQ2hyb21vIiwgYnkueSA9ICJjaHIiKQogICAgZGF0WywgUE9TZ2VuIDo9IFdpbkNlbnRlciArIHN0YXJ0XQogICAgZGF0WyxzdGFydCA6PSBOVUxMXSAjcmVtb3ZlIHN0YXJ0CiAgICAKICAgICNjYWxjdWxhdGUgcC12YWx1ZXMKICAgICMxLiB0aGV0YVcgbG9jaQogICAgZGF0W3RXZCA+IDAsIHRXZC5wIDo9IGNhbGNwRyh0V2QsIG51bGwkbWF4dFdkKSwgYnkgPSAuKENocm9tbywgV2luQ2VudGVyKV0gIyB0aGV0YVcgIGxvY2kKICAgIGRhdFt0V2QgPD0gMCwgdFdkLnAgOj0gY2FsY3BMKHRXZCwgbnVsbCRtaW50V2QpLCBieSA9IC4oQ2hyb21vLCBXaW5DZW50ZXIpXQogICAgIzIuIHRoZXRhIHBpCiAgICBkYXRbdFBkID4gMCwgdFBkLnAgOj0gY2FsY3BHKHRQZCwgbnVsbCRtYXh0UGQpLCBieSA9IC4oQ2hyb21vLCBXaW5DZW50ZXIpXSAjIHRoZXRhIHBpCiAgICBkYXRbdFBkIDw9IDAsIHRQZC5wIDo9IGNhbGNwTCh0UGQsIG51bGwkbWludFBkKSwgYnkgPSAuKENocm9tbywgV2luQ2VudGVyKV0KICAgIAogICAgI1RhamltYSdzIEQKICAgIGRhdFt0RGQgPiAwLCB0RGQucCA6PSBjYWxjcEcodERkLCBudWxsJG1heHREZCksIGJ5ID0gLihDaHJvbW8sIFdpbkNlbnRlcildICMgdGFqaW1hJ3MgRAogICAgZGF0W3REZCA8PSAwLCB0RGQucCA6PSBjYWxjcEwodERkLCBudWxsJG1pbnREZCksIGJ5ID0gLihDaHJvbW8sIFdpbkNlbnRlcildCgogICAgd3JpdGUuY3N2KGRhdCwgZmlsZT1nemZpbGUocGFzdGUwKCcuLi9PdXRwdXQvUGkvU2h1ZmZsZS90aGV0YV9zaXRlc2h1ZmZsZV8nLCBjb21iW3AsMV0sIl8iLGNvbWJbcCwyXSwnLmNzdi5neicpKSkKICAgIAogICAgRGF0YWxsPC1yYmluZChEYXRhbGwsIGRhdCkKfQoKd3JpdGUuY3N2KERhdGFsbCwgZmlsZT1nemZpbGUocGFzdGUwKCcuLi9PdXRwdXQvUGkvU2h1ZmZsZS90aGV0YV9zaXRlc2h1ZmZsZV9QV1Nfc3VtbWFyeS5jc3YuZ3onKSkpCmBgYCAgIAoKIyMgUGxvdCB0aGUgcmVzdWx0cyAgCgojIyMgQ2hhbmdlcyBpbiBQaS9UaGV0YS9EIGJldHdlZW4geWVhcnMgCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgojIyBQbG90IHRoZSByZXN1bHRzICMjCkRhdGFsbDwtZnJlYWQoJy4uL091dHB1dC9QaS9TaHVmZmxlL3RoZXRhX3NpdGVzaHVmZmxlX1BXU19zdW1tYXJ5LmNzdi5neicpCgp3aW5zeiA9IDVlNCAKCiNDaGFuZ2VzIGluIFBpIGJldHdlZW4geWVhcnMKRGF0YWxsJENocm9tbzwtZmFjdG9yKERhdGFsbCRDaHJvbW8sIGxldmVscz1jKHBhc3RlMCgiY2hyIiwxOjI2KSkpCkRhdGFsbCRwb3A8LWZhY3RvcihEYXRhbGwkcG9wLCBsZXZlbHM9YygiUFdTOTFfUFdTOTYiLCJQV1M5MV9QV1MwNyIsIlBXUzkxX1BXUzE3IiwiUFdTOTZfUFdTMDciLCJQV1M5Nl9QV1MxNyIsIlBXUzA3X1BXUzE3IikpCgpnZ3Bsb3QoRGF0YWxsLCBhZXMoUE9TZ2VuLCB0UGQvd2luc3osIGNvbG9yID0gQ2hyb21vKSkgKyAKICAgIGdlb21fcG9pbnQoc2l6ZSA9IDAuNSwgYWxwaGEgPSAwLjMpICsKICAgIGZhY2V0X3dyYXAofnBvcCwgbmNvbCA9IDEpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2xzLCBndWlkZT0ibm9uZSIpICsKICAgIHlsYWIoJ0NoYW5nZSBpbiBwaSBwZXIgc2l0ZScpK3hsYWIoIkNocm9tb3NvbWUiKSsKICAgIGdndGl0bGUoIkNoYW5nZXMgaW4gUGkiKSsKICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3M9Y2hybWF4JG1pZGRsZSwgbGFiZWxzPTE6MjYpKwogICAgdGhlbWVfYncoKQpnZ3NhdmUocGFzdGUwKCcuLi9PdXRwdXQvUGkvU2h1ZmZsZS9DaGFuZ2VzX2luX1BpX1BXUy5wbmcnKSwgd2lkdGggPSA3LjUsIGhlaWdodCA9IDksIGRwaSA9IDMwMCkKCiMgcGxvdCB0aGV0YV9XYXR0ZXJzb24gY2hhbmdlCmdncGxvdChEYXRhbGwsIGFlcyhQT1NnZW4sIHRXZC93aW5zeiwgY29sb3IgPSBDaHJvbW8pKSArIAogIGdlb21fcG9pbnQoc2l6ZSA9IDAuNSwgYWxwaGEgPSAwLjMpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY29scywgZ3VpZGU9Im5vbmUiKSArCiAgICBmYWNldF93cmFwKH5wb3AsIG5jb2wgPSAxKSArCiAgeWxhYignQ2hhbmdlIGluIFdhdHRlcnNvbnMgdGhldGEgcGVyIHNpdGUnKSt4bGFiKCJDaHJvbW9zb21lIikrCiAgZ2d0aXRsZSgiQ2hhbmdlcyBpbiBQaSIpKwogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jaHJtYXgkbWlkZGxlLCBsYWJlbHM9MToyNikrCiAgICB0aGVtZV9idygpCmdnc2F2ZSgnLi4vT3V0cHV0L1BpL1NodWZmbGUvQ2hhbmdlc19pbl90aGV0YVdfUFdTLnBuZycsIHdpZHRoID0gNy41LCBoZWlnaHQgPSA5LCBkcGkgPSAzMDApCgojIHBsb3QgVGFqaW1hJ3MgRCBjaGFuZ2UKZ2dwbG90KERhdGFsbCwgYWVzKFBPU2dlbiwgdERkLCBjb2xvciA9IENocm9tbykpICsgCiAgICBnZW9tX3BvaW50KHNpemUgPSAwLjUsIGFscGhhID0gMC4zKSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY29scyxndWlkZT0ibm9uZSIpICsKICAgIGZhY2V0X3dyYXAofnBvcCwgbmNvbCA9IDEpICsKICAgIHlsYWIoJ0NoYW5nZSBpbiBUYWppbWFzIEQgcGVyIHdpbmRvdycpK3hsYWIoIkNocm9tb3NvbWUiKSsKICAgIGdndGl0bGUoIkNoYW5nZXMgaW4gVGFqaW1hJ3MgRCIpKwogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jaHJtYXgkbWlkZGxlLCBsYWJlbHM9MToyNikrCiAgICB0aGVtZV9idygpCmdnc2F2ZSgnLi4vT3V0cHV0L1BpL1NodWZmbGUvQ2hhbmdlc19pbl9UYWppbWFzRF9QV1MucG5nJywgd2lkdGggPSA3LjUsIGhlaWdodCA9IDksIGRwaSA9IDMwMCkKCmBgYAohW10oLi4vT3V0cHV0L1BpL1NodWZmbGUvQ2hhbmdlc19pbl9QaV9QV1MucG5nKXt3aWR0aD03MCV9CgohW10oLi4vT3V0cHV0L1BpL1NodWZmbGUvQ2hhbmdlc19pbl90aGV0YVdfUFdTLnBuZyl7d2lkdGg9NzAlfQoKIVtdKC4uL091dHB1dC9QaS9TaHVmZmxlL0NoYW5nZXNfaW5fVGFqaW1hc0RfUFdTLnBuZyl7d2lkdGg9NzAlfQoKIyMjIFBsb3QgdGhlIHAtdmFsdWVzIGZvciBkaWZmZXJlbmNlcyBpbiBQL1RoZXRhIGFsb25nIHRoZSBnZW5vbWUgCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIHBsb3QgcGkgcC12YWx1ZSB2cy4gcG9zaXRpb24gCmNvbHMgPC0gYnJld2VyLnBhbCg0LCAnUGFpcmVkJylbcmVwKDE6MiwxMyldCkRhdGFsbCRDaHJvbW88LWZhY3RvcihEYXRhbGwkQ2hyb21vLCBsZXZlbHM9YyhwYXN0ZTAoImNociIsMToyNikpKQpEYXRhbGwkcG9wPC1mYWN0b3IoRGF0YWxsJHBvcCwgbGV2ZWxzPWMoIlBXUzkxX1BXUzk2IiwiUFdTOTFfUFdTMDciLCJQV1M5MV9QV1MxNyIsIlBXUzk2X1BXUzA3IiwiUFdTOTZfUFdTMTciLCJQV1MwN19QV1MxNyIpKQoKZ2dwbG90KERhdGFsbCwgYWVzKFBPU2dlbiwgLWxvZzEwKHRQZC5wKSpzaWduKHRQZCksIGNvbG9yID0gQ2hyb21vKSkgKyAKICAgIGdlb21fcG9pbnQoc2l6ZSA9IDAuNCwgYWxwaGEgPSAwLjMpICsKICAgIGZhY2V0X3dyYXAofnBvcCwgbmNvbCA9IDEpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2xzLCBndWlkZT0ibm9uZSIpICt4bGFiKCJDaHJvbW9zb21lIikrCiAgICB5bGFiKCJsb2cxMChQLXZhbHVlKSIpKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gbG9nMTAoMC4wNSksIGxpbmV0eXBlID0gJ2Rhc2hlZCcsIGNvbG9yID0gJ3JlZCcsc2l6ZT0wLjMpICsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IC1sb2cxMCgwLjA1KSwgbGluZXR5cGUgPSAnZGFzaGVkJywgY29sb3IgPSAncmVkJywgc2l6ZT0wLjMpKwogICAgZ2d0aXRsZSgiUC12YWx1ZXMgZm9yIGNoYW5nZXMgaW4gUGkiKSsKICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3M9Y2hybWF4JG1pZGRsZSwgbGFiZWxzPTE6MjYpKwogICAgdGhlbWVfYncoKQpnZ3NhdmUoJy4uL091dHB1dC9QaS9TaHVmZmxlL0NoYW5nZXNfaW5fUGkuc2l0ZXNodWZmbGUucC12YWx1ZXNfUFdTLnBuZycsIHdpZHRoID0gNy41LCBoZWlnaHQgPTExLCB1bml0cyA9ICdpbicsIGRwaSA9IDMwMCkKCgojIHBsb3QgdGhldGFXIHAtdmFsdWUgdnMuIHBvc2l0aW9uIChhbGwgbG9jaSkKZ2dwbG90KERhdGFsbCwgYWVzKFBPU2dlbiwgLWxvZzEwKHRXZC5wKSpzaWduKHRXZCksIGNvbG9yID0gQ2hyb21vKSkgKyAKICBnZW9tX3BvaW50KHNpemUgPSAwLjQsIGFscGhhID0gMC4zKSArCiAgZmFjZXRfd3JhcCh+cG9wLCBuY29sID0gMSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2xzLCBndWlkZT0ibm9uZSIpICt4bGFiKCJDaHJvbW9zb21lIikrCiAgICB5bGFiKCJsb2cxMChQLXZhbHVlKSIpKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IGxvZzEwKDAuMDUpLCBsaW5ldHlwZSA9ICdkYXNoZWQnLCBjb2xvciA9ICdyZWQnLCBzaXplPTAuMykgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IC1sb2cxMCgwLjA1KSwgbGluZXR5cGUgPSAnZGFzaGVkJywgY29sb3IgPSAncmVkJywgc2l6ZT0wLjMpKwogICAgICBnZ3RpdGxlKCJQLXZhbHVlcyBmb3IgY2hhbmdlcyBpbiBUaGV0YSIpKwogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jaHJtYXgkbWlkZGxlLCBsYWJlbHM9MToyNikrCiAgICB0aGVtZV9idygpCmdnc2F2ZSgnLi4vT3V0cHV0L1BpL1NodWZmbGUvQ2hhbmdlc19pbl90aGV0YVcuc2l0ZXNodWZmbGUucC12YWx1ZXNfUFdTLnBuZycsIHdpZHRoID0gNy41LCBoZWlnaHQgPTExLCB1bml0cyA9ICdpbicsIGRwaSA9IDMwMCkKCiNwbG90IFRhamFtYSdzIEQgcC12YWx1ZSB2cy4gcG9zaXRpb24KZ2dwbG90KERhdGFsbCwgYWVzKFBPU2dlbiwgLWxvZzEwKHREZC5wKSpzaWduKHREZCksIGNvbG9yID0gQ2hyb21vKSkgKyAKICAgIGdlb21fcG9pbnQoc2l6ZSA9IDAuNCwgYWxwaGEgPSAwLjMpICsKICAgIGZhY2V0X3dyYXAofnBvcCwgbmNvbCA9IDEpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2xzLCBndWlkZT0ibm9uZSIpICt4bGFiKCJDaHJvbW9zb21lIikrCiAgICB5bGFiKCJsb2cxMChQLXZhbHVlKSIpKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gbG9nMTAoMC4wNSksIGxpbmV0eXBlID0gJ2Rhc2hlZCcsICBjb2xvciA9ICdyZWQnLCBzaXplPTAuMykgKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gLWxvZzEwKDAuMDUpLCBsaW5ldHlwZSA9ICdkYXNoZWQnLCBjb2xvciA9ICdyZWQnLCBzaXplPTAuMykrCiAgICBnZ3RpdGxlKCJQLXZhbHVlcyBmb3IgY2hhbmdlcyBpbiBUYWppbWEncyBEIikrCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWNocm1heCRtaWRkbGUsIGxhYmVscz0xOjI2KSsKICAgIHRoZW1lX2J3KCkKZ2dzYXZlKCcuLi9PdXRwdXQvUGkvU2h1ZmZsZS9DaGFuZ2VzX2luX1RhamltYUQuc2l0ZXNodWZmbGUucC12YWx1ZXNfUFdTLnBuZycsIHdpZHRoID0gNy41LCBoZWlnaHQgPTExLCB1bml0cyA9ICdpbicsIGRwaSA9IDMwMCkKCmBgYAoKIVtdKC4uL091dHB1dC9QaS9TaHVmZmxlL0NoYW5nZXNfaW5fUGkuc2l0ZXNodWZmbGUucC12YWx1ZXNfUFdTLnBuZyl7d2lkdGg9NzAlfQoKCiFbXSguLi9PdXRwdXQvUGkvU2h1ZmZsZS9DaGFuZ2VzX2luX3RoZXRhVy5zaXRlc2h1ZmZsZS5wLXZhbHVlc19QV1MucG5nKXt3aWR0aD03MCV9CgohW10oLi4vT3V0cHV0L1BpL1NodWZmbGUvQ2hhbmdlc19pbl9UYWppbWFELnNpdGVzaHVmZmxlLnAtdmFsdWVzX1BXUy5wbmcpe3dpZHRoPTcwJX0KCiMjIEZpbmQgdGhlIHJlZ2lvbnMgd2l0aCBzaWduZmlpY2FudCBQLXZhbHVlcyAoT3V0bGllciByZWdpb25zKSAgCgojIyMgUGkKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBPdXRsaWVycwoKUGlfb3V0bGllcnM8LURhdGFsbFt0UGQucCA8IDAuMDUsXQpUaGV0YV9vdXRsaWVyczwtRGF0YWxsW3RXZC5wIDwgMC4wNSxdClRhamltYURfb3V0bGllcnM8LURhdGFsbFt0RGQucCA8IDAuMDUsXSAjbm8gb3V0bGllcnMKCiMgU3VtbWFyeSBwZXIgY2hyb21vc29tZSBwZXIgcG9wdWxhdGlvbgpwaTwtZGF0YS5mcmFtZSh0YWJsZShQaV9vdXRsaWVycyRwb3AsIFBpX291dGxpZXJzJENocm9tbykpCnRoZTwtZGF0YS5mcmFtZSh0YWJsZShUaGV0YV9vdXRsaWVycyRwb3AsIFRoZXRhX291dGxpZXJzJENocm9tbykpCkQ8LWRhdGEuZnJhbWUodGFibGUoVGFqaW1hRF9vdXRsaWVycyRwb3AsIFRhamltYURfb3V0bGllcnMkQ2hyb21vKSkKCiMgU3VtbWFyeSBwZXIgcG9wdWxhdGlvbgpwaTI8LWRhdGEuZnJhbWUodGFibGUoUGlfb3V0bGllcnMkcG9wKSkKdGhlMjwtZGF0YS5mcmFtZSh0YWJsZShUaGV0YV9vdXRsaWVycyRwb3ApKQpEczI8LWRhdGEuZnJhbWUodGFibGUoVGFqaW1hRF9vdXRsaWVycyRwb3ApKQoKCiNwbG90IFBXUzkxLTk2LCA5Ni0wNywgYW5kIDA3LTE3CnlyczwtYygiUFdTOTFfUFdTOTYiLCJQV1M5Nl9QV1MwNyIsIlBXUzA3X1BXUzE3IikKY29sMzwtYnJld2VyLnBhbCg1LCJQdVJkIilbYygyLDMsNSldCmRpdjE8LWRpdmVyZ2luZ19oY2woNiwgcGFsZXR0ZT0iQmx1ZS1SZWQiKQojcmV2ZXJzZSB0aGUgY29sb3IKZGl2MjwtcmV2KGRpdjEpCgpwaXM8LXBpW3BpJFZhcjEgJWluJSB5cnMsXQpwaXMkVmFyMTwtZmFjdG9yKHBpcyRWYXIxLCBsZXZlbHM9eXJzKQpnZ3Bsb3QocGlzLCBhZXMoeD1WYXIyLCB5PUZyZXEsIGZpbGw9VmFyMSkpKwogICAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoPTAuOCkpKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWNvbDMpKwogICAgdGhlbWVfY2xhc3NpYygpKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpKwogICAgZ2d0aXRsZShleHByZXNzaW9uKHBhc3RlKCJDaGFuZ2VzIGluICIsIHBpKSkpKwogICAgeGxhYignJykreWxhYignTnVtYmVyIG9mIHJlZ2lvbnMgd2l0aCBQPDAuMDUnKQpnZ3NhdmUoIi4uL091dHB1dC9QaS9TaHVmZmxlL1BpX3NpZ25pZmljYW50X3BlckNocm9tX3BlclBvcC5wbmciLCB3aWR0aCA9IDgsIGhlaWdodCA9IDQsIGRwaT0zMDApIAoKIyBQZXIgcG9wdWxhdGlvbiBjb21wYXJpc29uCmdncGxvdChwaTIsIGFlcyh4PVZhcjEsIHk9RnJlcSwgZmlsbD1WYXIxKSkrCiAgICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIscG9zaXRpb249cG9zaXRpb25fZG9kZ2Uod2lkdGg9MC44KSkrCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9ZGl2MSkrCiAgICB0aGVtZV9jbGFzc2ljKCkrCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3Q9MSksIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkrCiAgICBnZ3RpdGxlKGV4cHJlc3Npb24ocGFzdGUoIkNoYW5nZXMgaW4gIiwgcGkpKSkrCiAgICB4bGFiKCcnKSt5bGFiKCdOdW1iZXIgb2YgcmVnaW9ucyB3aXRoIFA8MC4wNScpCmdnc2F2ZSgiLi4vT3V0cHV0L1BpL1NodWZmbGUvUGlfc2lnbmlmaWNhbnRfcGVyQ29tcGFyaXNvbi5wbmciLCB3aWR0aCA9IDUsIGhlaWdodCA9IDQsIGRwaT0zMDApIAoKI29yZGVyZWQKcGkzPC1waTJbb3JkZXIocGkyJEZyZXEsIGRlY3JlYXNpbmcgPSBUKSxdCnBpMyRWYXIxPC1mYWN0b3IocGkzJFZhcjEsIGxldmVscz1wYXN0ZTAodW5pcXVlKHBpMyRWYXIxKSkpCmdncGxvdChwaTMsIGFlcyh4PVZhcjEsIHk9RnJlcSwgZmlsbD1WYXIxKSkrCiAgICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIscG9zaXRpb249cG9zaXRpb25fZG9kZ2Uod2lkdGg9MC44KSkrCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9ZGl2MikrCiAgICB0aGVtZV9jbGFzc2ljKCkrCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3Q9MSksIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkrCiAgICBnZ3RpdGxlKGV4cHJlc3Npb24ocGFzdGUoIkNoYW5nZXMgaW4gIiwgcGkpKSkrCiAgICB4bGFiKCcnKSt5bGFiKCdOdW1iZXIgb2YgcmVnaW9ucyB3aXRoIFA8MC4wNScpCmdnc2F2ZSgiLi4vT3V0cHV0L1BpL1NodWZmbGUvUGlfc2lnbmlmaWNhbnRfcGVyQ29tcGFyaXNvbl9vcmRlcmVkLnBuZyIsIHdpZHRoID0gNSwgaGVpZ2h0ID0gNCwgZHBpPTMwMCkgCgojQXNzaWduIGNvbG9ycyB0byB0aGUgY29tcGFyaXNvbiBncm91cApuYW1lcyhkaXYyKTwtIHVuaXF1ZShwaTMkVmFyMSkKCgpgYGAKIVtdKC4uL091dHB1dC9QaS9TaHVmZmxlL1BpX3NpZ25pZmljYW50X3BlckNvbXBhcmlzb25fb3JkZXJlZC5wbmcpICAKCgohW10oLi4vT3V0cHV0L1BpL1NodWZmbGUvUGlfc2lnbmlmaWNhbnRfcGVyQ2hyb21fcGVyUG9wLnBuZykgIAoKCiMjIyBUaGV0YQoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCiNUaGV0ZWEKdGhzPC10aGVbdGhlJFZhcjEgJWluJSB5cnMsXQp0aHMkVmFyMTwtZmFjdG9yKHRocyRWYXIxLCBsZXZlbHM9eXJzKQpnZ3Bsb3QodGhzLCBhZXMoeD1WYXIyLCB5PUZyZXEsIGZpbGw9VmFyMSkpKwogICAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoPTAuOCkpKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWNvbDMpKwogICAgdGhlbWVfY2xhc3NpYygpKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpKwogICAgZ2d0aXRsZShwYXN0ZTAoIkNoYW5nZXMgaW4gdGhldGEiKSkrCiAgICB4bGFiKCcnKSt5bGFiKCdOdW1iZXIgb2YgcmVnaW9ucyB3aXRoIFA8MC4wNScpCmdnc2F2ZSgiLi4vT3V0cHV0L1BpL1NodWZmbGUvVGhldGFfc2lnbmlmaWNhbnRfcGVyQ2hyb21fcGVyUG9wLnBuZyIsIHdpZHRoID0gNSwgaGVpZ2h0ID0gMywgZHBpPTMwMCkgCgpnZ3Bsb3QodGhlMiwgYWVzKHg9VmFyMSwgeT1GcmVxLCBmaWxsPVZhcjEpKSsKICAgIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5Iixwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aD0wLjgpKSsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1kaXYxKSsKICAgIHRoZW1lX2NsYXNzaWMoKSsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LCBoanVzdD0xKSwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSsKICAgIGdndGl0bGUocGFzdGUoIkNoYW5nZXMgaW4gdGhldGEiKSkrCiAgICB4bGFiKCcnKSt5bGFiKCdOdW1iZXIgb2YgcmVnaW9ucyB3aXRoIFA8MC4wNScpCmdnc2F2ZSgiLi4vT3V0cHV0L1BpL1NodWZmbGUvVGhldGFfc2lnbmlmaWNhbnRfcGVyQ29tcGFyaXNvbi5wbmciLCB3aWR0aCA9IDUsIGhlaWdodCA9IDQsIGRwaT0zMDApIAoKCnRoZTM8LXRoZTJbb3JkZXIodGhlMiRGcmVxLCBkZWNyZWFzaW5nID0gVCksXQp0aGUzJFZhcjE8LWZhY3Rvcih0aGUzJFZhcjEsIGxldmVscz1wYXN0ZTAodW5pcXVlKHRoZTMkVmFyMSkpKQoKZ2dwbG90KHRoZTMsIGFlcyh4PVZhcjEsIHk9RnJlcSwgZmlsbD1WYXIxKSkrCiAgICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIscG9zaXRpb249cG9zaXRpb25fZG9kZ2Uod2lkdGg9MC44KSkrCiAgICBzY2FsZV9maWxsX21hbnVhbChuYW1lID0gIlZhcjEiLHZhbHVlcyA9IGRpdjIpKwogICAgdGhlbWVfY2xhc3NpYygpKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpKwogICAgZ2d0aXRsZShwYXN0ZSgiQ2hhbmdlcyBpbiB0aGV0YSIpKSsKICAgIHhsYWIoJycpK3lsYWIoJ051bWJlciBvZiByZWdpb25zIHdpdGggUDwwLjA1JykKZ2dzYXZlKCIuLi9PdXRwdXQvUGkvU2h1ZmZsZS9UaGV0YV9zaWduaWZpY2FudF9wZXJDb21wYXJpc29uX29yZGVyZWQucG5nIiwgd2lkdGggPSA1LCBoZWlnaHQgPSA0LCBkcGk9MzAwKSAKCgoKYGBgCiFbXSguLi9PdXRwdXQvUGkvU2h1ZmZsZS9UaGV0YV9zaWduaWZpY2FudF9wZXJDb21wYXJpc29uLnBuZykKCiFbXSguLi9PdXRwdXQvUGkvU2h1ZmZsZS9UaGV0YV9zaWduaWZpY2FudF9wZXJDaHJvbV9wZXJQb3AucG5nKQoKCiMjIyBUYWppbWEncyBEIC0gTm8gcmVnaW9ucyB3aXRoIFAgPCAwLjA1ICAKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCiMgVGFqaW1hJ3MgRApnZ3Bsb3QoRHMyLCBhZXMoeD1WYXIxLCB5PUZyZXEsIGZpbGw9VmFyMSkpKwogICAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoPTAuOCkpKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWRpdjEpKwogICAgdGhlbWVfY2xhc3NpYygpKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpKwogICAgZ2d0aXRsZShwYXN0ZTAoIkNoYW5nZXMgaW4gVGFqaW1hJ3MgRCIpKSsKICAgIHhsYWIoJycpK3lsYWIoJ051bWJlciBvZiByZWdpb25zIHdpdGggUDwwLjA1JykKZ2dzYXZlKCIuLi9PdXRwdXQvUGkvU2h1ZmZsZS9UYWppbWFEX3NpZ25pZmljYW50X3BlckNvbXBhcmlzb24ucG5nIiwgd2lkdGggPSA1LCBoZWlnaHQgPSA0LCBkcGk9MzAwKSAKCgpEMjwtRFtEJFZhcjEgJWluJSB5cnMsXQpEMiRWYXIxPC1mYWN0b3IoRDIkVmFyMSwgbGV2ZWxzPXlycykKZ2dwbG90KEQyLCBhZXMoeD1WYXIyLCB5PUZyZXEsIGZpbGw9VmFyMSkpKwogICAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoPTAuOCkpKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWNvbDMpKwogICAgdGhlbWVfY2xhc3NpYygpKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpKwogICAgIGdndGl0bGUocGFzdGUwKCJDaGFuZ2VzIGluIFRhamltYSdzIEQiKSkrCiAgICB4bGFiKCcnKSt5bGFiKCdOdW1iZXIgb2YgcmVnaW9ucyB3aXRoIFA+MC4wNScpCiNnZ3NhdmUoIi4uL091dHB1dC9QaS9TaHVmZmxlL1RhamltYURfc2lnbmlmaWNhbnRfcGVyQ2hyb21fcGVyUG9wLnBuZyIsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNCwgZHBpPTMwMCkgCgpgYGAKCi0gTW9zdCBkaWZmZXJlbmNlcyBleGlzdCBiZXR3ZWVuIDE5OTYgYW5kIDIwMDcKLSBDaHIyNSBoYXMgdGhlIG1vc3Qgc2lnbmlmaWNhbnQgcmVnaW9ucyBmb3IgY2hhbmdlcyBpbiBQaSBhbmQgVGhldGEKCjxicj4KPGJyPgoKIyBGc3QgZ2Vub21lLXNjYW4gdXNpbmcgYSBudWxsIG1vZGVsCiogZnJvbSBQaW5za3kgZXQgYWwuIDIwMjEgIGh0dHBzOi8vZ2l0aHViLmNvbS9waW5za3lsYWIvY29kRXZvbAoqIENyZWF0ZSBhIG51bGwgZGlzdHJpYnV0aW9uIG9mIGV4cGVjdGVkIG1heGltdW0gRnN0CiogRGVmaW5lIGEgZ2Vub21lLXdpZGUgcC12YWx1ZSBmb3IgZWFjaCByZWdpb24gYXMgKHIrMSkvKG4rMSksIHdoZXJlIHIgd2FzIHRoZSBudW1iZXIgb2YgbnVsbCBzaW11bGF0aW9ucyB3aXRoIG1heGltdW0gY2hhbmdlIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byB0aGUgZW1waXJpY2FsIHZhbHVlIGFuZCBuIHdhcyB0aGUgbnVtYmVyIG9mIHNodWZmbGVzCgojIyBTaHVmZmxlIEZzdCBhbmQgY3JlYXRlIGEgbnVsbCBtb2RlbCBvZiBtYXggRnN0CiogQmFzZWQgb24gYW5nc2QgcGVyc2l0ZSBGc3Qgb3V0cHV0CgoxLiBBZnRlciBydW5uaW5nIGFuZ3NkIChyZWFsU0ZTKSwgcHJpbnQgYSBwZXJzaXRlIEZzdCBmaWxlIApgYGB7YmFzaH0KI3J1biBGc3RQV1NwcmludC5zaAoKL2hvbWUvamFtY2dpcnIvYXBwcy9hbmdzZC9taXNjL3JlYWxTRlMgZnN0IHByaW50ICAvaG9tZS9rdGlzdC9waC9kYXRhL2FuZ3NkL2FuYWx5c2lzL2ZzdF9QV1M5MV9QV1MwN19wZXJzaXRlX21hZjAwLmZzdC5pZHggPiAvaG9tZS9rdGlzdC9waC9kYXRhL2FuZ3NkL2FuYWx5c2lzL2ZzdF9QV1M5MV9QV1MwN19wZXJzaXRlX21hZjAwLnR4dApiZ3ppcCAvaG9tZS9rdGlzdC9waC9kYXRhL2FuZ3NkL2FuYWx5c2lzL2ZzdF9QV1M5MV9QV1MwN19wZXJzaXRlX21hZjAwLnR4dAoKYGBgCgoyLiBSdW4gRnN0X3NodWZmbGVfcHdzLlIgYXQgRmFybSAoc2x1cm0gc2NyaXB0OiBhbmdzZF9mc3Rfc2l0ZXNodWZmbGVfbnVsbC5zaCkgIAoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBGcm9tIGh0dHBzOi8vZ2l0aHViLmNvbS9waW5za3lsYWIvY29kRXZvbCBhbmdzZF9mc3Rfc2l0ZXNodWZmbGVfbnVsbC5yCgojIHNodWZmbGUgQU5HU0QgcGVyc2l0ZSBGU1QgQSBhbmQgQiB2YWx1ZXMgYWNyb3NzIHNpdGVzIGFuZCBjYWxjdWxhdGUgd2luZG93ZWQgRlNUIHRvIGdldCBhIG51bGwgZGlzdHJpYnV0aW9uIG9mIG1heCBnZW5vbWUtd2lkZSBGU1QKIyBuZWVkIGZzdCBwZXJzaXRlIG91dHB1dCBmcm9tIGFuZ3NkIGZzdF8qX3BlcnNpdGVfbWFmMDAudHh0Lmd6IGZpbGVzCgojIHRvIHJ1biBvbiBmYXJtCgoKIyMjIyMgUiBjb2RlICAjIyMjIyMjIAoKIyBwYXJhbWV0ZXJzCndpbnN6IDwtIDUwMDAwICMgd2luZG93IHNpemUKd2luc3RwIDwtIDEwMDAwICMgd2luZG93IHN0ZXAKbnJlcCA8LSAxMDAwICMgbnVtYmVyIG9mIHJlc2h1ZmZsZXMKbWlubG9jaSA8LSAxMCAjIG1pbmltdW0gbnVtYmVyIG9mIGxvY2kgcGVyIHdpbmRvdyB0byBjb25zaWRlcgoKCiMgbG9hZCBmdW5jdGlvbnMKcmVxdWlyZShkYXRhLnRhYmxlKQoKCiMjIyMjIyMjIyMjIyMKIyBQcmVwIGRhdGEKIyMjIyMjIyMjIyMjIwojIGxvYWQgZnN0IEEvQiBkYXRhCiNjYW4gPC0gZnJlYWQoJ2FuYWx5c2lzL0Nhbl80MC5DYW5fMTQuZnN0LkFCLmd6JykKI3NldG5hbWVzKGNhbiwgYygnQ0hST00nLCAnUE9TJywgJ0EnLCAnQicpKQoKcHdzOTE5NiA8LSBmcmVhZCgnL2hvbWUva3Rpc3QvcGgvZGF0YS9hbmdzZC9hbmFseXNpcy9mc3RfUFdTOTFfUFdTOTZfcGVyc2l0ZV9tYWYwMC50eHQuZ3onKQpzZXRuYW1lcyhwd3M5MTk2LCBjKCdDSFJPTScsICdQT1MnLCAnQScsICdCJykpCnB3czkxMDcgPC0gZnJlYWQoJy9ob21lL2t0aXN0L3BoL2RhdGEvYW5nc2QvYW5hbHlzaXMvZnN0X1BXUzkxX1BXUzA3X3BlcnNpdGVfbWFmMDAudHh0Lmd6JykKc2V0bmFtZXMocHdzOTEwNywgYygnQ0hST00nLCAnUE9TJywgJ0EnLCAnQicpKQpwd3M5MTE3IDwtIGZyZWFkKCcvaG9tZS9rdGlzdC9waC9kYXRhL2FuZ3NkL2FuYWx5c2lzL2ZzdF9QV1M5MV9QV1MxN19wZXJzaXRlX21hZjAwLnR4dC5neicpCnNldG5hbWVzKHB3czkxMTcsIGMoJ0NIUk9NJywgJ1BPUycsICdBJywgJ0InKSkKcHdzOTYwNyA8LSBmcmVhZCgnL2hvbWUva3Rpc3QvcGgvZGF0YS9hbmdzZC9hbmFseXNpcy9mc3RfUFdTOTZfUFdTMDdfcGVyc2l0ZV9tYWYwMC50eHQuZ3onKQpzZXRuYW1lcyhwd3M5NjA3LCBjKCdDSFJPTScsICdQT1MnLCAnQScsICdCJykpCnB3czk2MTcgPC0gZnJlYWQoJy9ob21lL2t0aXN0L3BoL2RhdGEvYW5nc2QvYW5hbHlzaXMvZnN0X1BXUzk2X1BXUzE3X3BlcnNpdGVfbWFmMDAudHh0Lmd6JykKc2V0bmFtZXMocHdzOTYxNywgYygnQ0hST00nLCAnUE9TJywgJ0EnLCAnQicpKQpwd3MwNzE3IDwtIGZyZWFkKCcvaG9tZS9rdGlzdC9waC9kYXRhL2FuZ3NkL2FuYWx5c2lzL2ZzdF9QV1MwN19QV1MxN19wZXJzaXRlX21hZjAwLnR4dC5neicpCnNldG5hbWVzKHB3czA3MTcsIGMoJ0NIUk9NJywgJ1BPUycsICdBJywgJ0InKSkKClBXUzwtbGlzdCgpClBXU1tbMV1dPC1wd3M5MTk2ClBXU1tbMl1dPC1wd3M5MTA3ClBXU1tbM11dPC1wd3M5MTE3ClBXU1tbNF1dPC1wd3M5NjA3ClBXU1tbNV1dPC1wd3M5NjE3IApQV1NbWzZdXTwtcHdzMDcxNyAKICAgIAogCiMgY3JlYXRlIG5ldyBjb2x1bW5zIGFzIGluZGljZXMgZm9yIHdpbmRvd3MKCmZvciAoaSBpbiAxOiBsZW5ndGgoUFdTKSl7CiAgICBkZjwtUFdTW1tpXV0KICAgIGZvcihqIGluIDE6KHdpbnN6L3dpbnN0cCkpewogICAgICAgIGRmWywgKHBhc3RlMCgnd2luJywgaikpIDo9IGZsb29yKChQT1MgLSAoai0xKSp3aW5zdHApL3dpbnN6KSp3aW5zeiArIHdpbnN6LzIgKyAoai0xKSp3aW5zdHBdCiAgICB9CiAgICBQV1NbW2ldXTwtZGYKfQoKIyBtYXJrIHdpbmRvd3Mgd2l0aCA8IG1pbmxvY2kgZm9yIHJlbW92YWwKcmVtIDwtIHJlcCgwLCA2KSAjIG51bWJlciBvZiB3aW5kb3dzIHJlbW92ZWQgZm9yIGVhY2ggb2YgdGhlIDYgY29tcGFyaXNvbnMKCmZvcihpIGluIDE6IGxlbmd0aChQV1MpKXsKICAgIHB3PC1QV1NbW2ldXQogICAgZm9yKGogaW4gMTood2luc3ovd2luc3RwKSl7CiAgICAgICAgcHd3aW4gPC0gcHdbLCAuKG5zbnBzID0gbGVuZ3RoKFBPUykpLCBieSA9IC4od2luID0gZ2V0KHBhc3RlMCgnd2luJywgaikpKV0gIyBjYWxjIG51bSBzbnBzIHBlciB3aW5kb3cKICAgICAgICByZW1bMV0gPC0gcmVtWzFdICsgcHd3aW5bLCBzdW0obnNucHMgPCBtaW5sb2NpKV0gIyByZWNvcmQgbnVtYmVyIHRvIGJlIHJlbW92ZWQKICAgICAgICBwd3dpblssIChwYXN0ZTAoJ3dpbicsIGosICdrZWVwJykpIDo9IDFdICMgY3JlYXRlIGNvbCB0byBtYXJrIHdoaWNoIHdpbmRvd3MgdG8ga2VlcAogICAgICAgIHB3d2luW25zbnBzIDwgbWlubG9jaSwgKHBhc3RlMCgnd2luJywgaiwgJ2tlZXAnKSkgOj0gMF0gIyBtYXJrIHdpbmRvd3MgdG8gcmVtb3ZlCiAgICAgICAgcHd3aW5bLCBuc25wcyA6PSBOVUxMXSAjIGRyb3AgY29sdW1uCiAgICAgICAgc2V0bmFtZXMocHd3aW4sICJ3aW4iLCBwYXN0ZTAoJ3dpbicsIGopKSAjIGNoYW5nZSBjb2wgbmFtZQogICAgICAgIHB3IDwtIG1lcmdlKHB3LCBwd3dpbiwgYnkgPSBwYXN0ZTAoJ3dpbicsIGopLCBhbGwueCA9IFRSVUUpICMgbWVyZ2Uga2VlcGVyIGNvbCBiYWNrIHRvIGZ1bGwgZGF0YXNldAogICAgfQogICAgUFdTW1tpXV08LXB3Cn0KCnJlbSAjIG51bWJlciBvZiB3aW5kb3dzIHJlbW92ZWQgZm9yIGVhY2ggY29tcGFyaXNvbgoKCgoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgc2h1ZmZsZSBhbmQgcmVjYWxjIHdpbmRvd2VkIEZTVAojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKY29sbm1zIDwtIGMoJ0NIUk9NJywgJ1BPUycsIHBhc3RlMCgnd2luJywgMTood2luc3ovd2luc3RwKSksIHBhc3RlMCgnd2luJywgMTood2luc3ovd2luc3RwKSwgJ2tlZXAnKSkgIyBsaXN0IG9mIGNvbHVtbiBuYW1lcyB3ZSB3YW50IG91dCBvZiB0aGUgYmFzZSBkYXRhLnRhYmxlCgojIFBXUzA3LTE3CnBvcHM8LWMoIlBXUzkxLjk2IiwiUFdTOTEuMDciLCJQV1M5MS4xNyIsIlBXUzk2LjA3IiwiUFdTOTYuMTciLCJQV1MwNy4xNyIpCgoKZm9yKHAgaW4gMTpsZW5ndGgoUFdTKSl7CiAgICBwcmludChwYXN0ZTAoJ1N0YXJ0aW5nICcsIHBvcHNbcF0pKQoKICAgIHB3PC1QV1NbW3BdXQogICAgZm9yKGkgaW4gMTpucmVwKXsKICAgICAgICBjYXQoaSk7IGNhdCgnICcpCiAgICAgICAgIyBjcmVhdGUgbmV3IGRhdGFzZXQKICAgICAgICBpbmRzIDwtIHNhbXBsZSgxOm5yb3cocHcpLCBucm93KHB3KSwgcmVwbGFjZSA9IEZBTFNFKQogICAgICAgIHRlbXAgPC0gY2JpbmQocHdbLCAuLmNvbG5tc10sIHB3W2luZHMsIC4oQSwgQildKSAjIHNodWZmbGUgRlNUcyBhY3Jvc3MgcG9zaXRpb25zCiAgICAgICAgCiAgICAgICAgIyBjYWxjIGZzdCBmb3IgZWFjaCB3aW5kb3cgdG8ga2VlcAogICAgICAgIGZvcihqIGluIDE6KHdpbnN6L3dpbnN0cCkpewogICAgICAgICAgICB0ZW1wMiA8LSB0ZW1wW2dldChwYXN0ZTAoJ3dpbicsIGosICdrZWVwJykpID09IDEsIF0gIyB0cmltIHRvIHdpbmRvd3MgdG8ga2VlcC4gY2FuJ3QgY29tYmluZSB3aXRoIG5leHQgbGluZSBmb3Igc29tZSByZWFzb24uCiAgICAgICAgICAgIGlmKGogPT0xKSB0ZW1wZnN0cyA8LSB0ZW1wMlssIC4oZnN0ID0gc3VtKEEpL3N1bShCKSksIGJ5ID0gLihDSFJPTSwgUE9TID0gZ2V0KHBhc3RlMCgnd2luJywgaikpKV0KICAgICAgICAgICAgaWYoaiA+IDEpIHRlbXBmc3RzIDwtIHJiaW5kKHRlbXBmc3RzLCB0ZW1wMlssIC4oZnN0ID0gc3VtKEEpL3N1bShCKSksIGJ5ID0gLihDSFJPTSwgUE9TID0gZ2V0KHBhc3RlMCgnd2luJywgaikpKV0pCiAgICAgICAgfQogICAgICAgIAogICAgICAgICMgc2F2ZSB0aGUgbWF4IHdpbmRvd2VkIGZzdAogICAgICAgICMgZXhjbHVkZSB3aW5kb3dzIHdpdGggbmVnYXRpdmUgbWlkcG9pbnRzCiAgICAgICAgaWYoaSA9PSAxKSBtYXhmc3QgPC0gdGVtcGZzdHNbUE9TID4gMCwgbWF4KGZzdCwgbmEucm0gPSBUUlVFKV0JCiAgICAgICAgaWYoaSA+IDEpIG1heGZzdCA8LSBjKG1heGZzdCwgdGVtcGZzdHNbUE9TID4gMCwgbWF4KGZzdCwgbmEucm0gPSBUUlVFKV0pCiAgICB9CgogICAgcHJpbnQocGFzdGUoJ01heDonLCBtYXgobWF4ZnN0LCBuYS5ybSA9IFRSVUUpLCAnOyA5NXRoOicsIHF1YW50aWxlKG1heGZzdCwgcHJvYiA9IDAuOTUsIG5hLnJtID0gVFJVRSkpKQogICAgCiAgICB3cml0ZS5jc3YobWF4ZnN0LCBnemZpbGUocGFzdGUwKCcvaG9tZS9rdGlzdC9waC9kYXRhL2FuZ3NkL2FuYWx5c2lzLycscG9wc1twXSwgJ19zaXRlc2h1dWZmbGUuY3N2Lmd6JykpLCByb3cubmFtZXMgPSBGQUxTRSkKICAgIHJtKG1heGZzdCkKfQoKYGBgCgoKIyMgQXNzZXNzIHRoZSByZXN1bHRzIGZyb20gc2l0ZSByZXNodWZmbGVkIEZzdCAKTmVlZCAKLSBzaXRlaHVmZmxlIHJlc3VsdHMgKmZzdF9zaXRlc2h1dWZmbGUuY3N2Lmd6Ci0gd2luZG93LWJhc2VkIEZzdCByZXN1bHRzIGZyb20gYW5nc2QgKl81MGtXaW5kb3dfbWFmMDAKLSBwZXJzaXRlIEZzdCBmaWxlcyBhZnRlciBMRCBwcnVuaW5nICh3aXRoIEFCIGluZm8pICpfcGVyc2l0ZV9tYWYwMF9sZHRyaW0uY3N2Lmd6IAoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KI2Zyb20gaHR0cHM6Ly9naXRodWIuY29tL3BpbnNreWxhYi9jb2RFdm9sCgojIHBhcmFtZXRlcnMKbWlubG9jaSA8LSAxMCAKd2luc3ogPC0gNTAwMDAgIyB3aW5kb3cgc2l6ZQp3aW5zdHAgPC0gMTAwMDAgIyB3aW5kb3cgc3RlcAoKIyBsb2FkIGZ1bmN0aW9ucwpyZXF1aXJlKGRhdGEudGFibGUpCnJlcXVpcmUoZ2dwbG90MikKCmNhbGNwIDwtIGZ1bmN0aW9uKGZzdCwgbnVsbCkgcmV0dXJuKChzdW0obnVsbCA+IGZzdCkrMSkvKGxlbmd0aChudWxsKSsxKSkgIyBlcXVhdGlvbiBmcm9tIE5vcnRoIGV0IGFsLiAyMDAyIEFtIEogSHVtIEdlbgoKIyByZWFkIGluIGFuZCBwcmVwIGRhdGEKeWVhcnM8LWMoIlBXUzkxIiwiUFdTOTYiLCJQV1MwNyIsIlBXUzE3IikKY29tYjwtdChjb21ibih5ZWFycywgMikpCgojIGNvbnRpbnVvdXMgbnVjbGVvdGlkZSBwb3NpdGlvbiBmb3IgdGhlIHdob2xlIGdlbm9tZQpjaHJtYXggPC0gZnJlYWQoJy4uL0RhdGEvbmV3X3ZjZi9jaHJfc2l6ZXMuYmVkJykKY2hybWF4PC1jaHJtYXhbLC0yXQpjb2xuYW1lcyhjaHJtYXgpPC1jKCJjaHIiLCAibGVuIikKY2hybWF4JHN0YXJ0PC1jKDAsY3Vtc3VtKGNocm1heCRsZW4pWzE6KG5yb3coY2hybWF4KS0xKV0pCnNldGtleShjaHJtYXgsIGNocikKCnBydW5lZEZzdF9ndzwtZGF0YS5mcmFtZShwb3AxPWNvbWJbLDFdLHBvcDI9Y29tYlssMl0pCiNmb3IgKHAgaW4gMTogbnJvdyhjb21iKSl7CiAgICBmb3IgKHAgaW4gMTo1KXsKICAgICNnZW5vbWUtd2lkZSBtYXggRnN0IGZyb20gcmVzaHVmZmxpbmcgKHVubGlua2VkIHNpdGVzKQogICAgbnVsbDwtZnJlYWQocGFzdGUwKCdEYXRhL3NodWZmbGUvJywgY29tYltwLDFdLCIuIixjb21iW3AsMl0sJ19mc3Rfc2l0ZXNodXVmZmxlLmNzdi5neicpKQogICAgI3dpbmRvdy1iYXNlZCBGc3QgZnJvbSBhbmdzZCAgICAgICAgICAgIAogICAgZnN0d2luIDwtIGZyZWFkKHBhc3RlMCgnRGF0YS9uZXdfdmNmL2FuZ3NkL2Zyb21WQ0YvMkQvZnN0XycsY29tYltwLDFdLCJfIixjb21iW3AsMl0sJ181MGtXaW5kb3dfbWFmMDAnKSwgaGVhZGVyID0gRkFMU0UsIGNvbC5uYW1lcyA9IGMoJ3JlZ2lvbicsICdjaHInLCAnbWlkUG9zJywgJ05zaXRlcycsICdmc3QnKSkgIyBhbGwgc2l0ZXMKICAgICNwZXJzaXRlIGZzdCAoQUIpIC1wcnVuZWQgc2l0ZXMKICAgIEFCIDwtIGZyZWFkKHBhc3RlMCgnRGF0YS9zaHVmZmxlL2ZzdF8nLGNvbWJbcCwxXSwiXyIsY29tYltwLDJdLCdfcGVyc2l0ZV9tYWYwMF9sZHRyaW0uY3N2Lmd6JykpCiAgICAKICAgICMgbWVyZ2UgbnVjbGVvdGlkZSBwb3NpdGlvbiBpbnRvIHRoZSBmcmVxdWVuY3kgZmlsZXMKICAgIHNldGtleShBQiwgQ0hST00pCiAgICBBQiA8LSBBQltjaHJtYXhbLCAuKENIUk9NID0gY2hyLCBzdGFydCldLCBdCiAgICBBQlssIHBvc2dlbiA6PSBQT1MgKyBzdGFydF0KICAgIEFCWyxzdGFydCA6PSBOVUxMXQogICAgCiAgICAjIENhbGMgZ2Vub21lLXdpZGUgRlNUCiAgICBwcnVuZWRGc3RfZ3ckZ3dGc3RbcF08LUFCWyFpcy5uYShBKSwgc3VtKEEpL3N1bShCKV0KICAgIAogICAgIyBDYWxjIHdpbmRvd2VkIEZTVAogICAgIyBjcmVhdGUgbmV3IGNvbHVtbnMgYXMgaW5kaWNlcyBmb3Igd2luZG93cwogICAgZm9yKGogaW4gMTood2luc3ovd2luc3RwKSl7CiAgICAgICAgQUJbLCAocGFzdGUwKCd3aW4nLCBqKSkgOj0gZmxvb3IoKFBPUyAtIChqLTEpKndpbnN0cCkvd2luc3opKndpbnN6ICsgd2luc3ovMiArIChqLTEpKndpbnN0cF0KICAgIH0KICAgIAogICAgIyBjYWxjIGZzdCBhbmQgIyBzbnBzIHBlciB3aW5kb3cKICAgIGZvcihqIGluIDE6KHdpbnN6L3dpbnN0cCkpewogICAgICAgIGlmKGogPT0xKXsKICAgICAgICAgICAgZnN0d2luIDwtIEFCWywgLihmc3QgPSBzdW0oQSkvc3VtKEIpLCBubG9jaSA9IGxlbmd0aChQT1MpKSwgYnkgPSAuKENIUk9NLCBtaWRQb3MgPSBnZXQocGFzdGUwKCd3aW4nLCBqKSkpXQogICAgICAgIH0gCiAgICAgICAgaWYoaiA+IDEpewogICAgICAgICAgICBmc3R3aW4gPC0gcmJpbmQoZnN0d2luLCBBQlssIC4oZnN0ID0gc3VtKEEpL3N1bShCKSwgbmxvY2kgPSBsZW5ndGgoUE9TKSksIGJ5ID0gLihDSFJPTSwgbWlkUG9zID0gZ2V0KHBhc3RlMCgnd2luJywgaikpKV0pCiAgICAgICAgfSAKICAgIH0KICAgIAogICAgIyMgbnVsbCBtb2RlbCBzdGF0cwogICAgZnN0YXRzPC1udWxsWywgLihtYXggPSBtYXgoeCksIHU5NSA9IHF1YW50aWxlKHgsIHByb2JzID0gMC45NSkpXQogICAgcHJ1bmVkRnN0X2d3JG51bGwuRnN0bWF4W3BdPC1mc3RhdHMkbWF4WzFdCiAgICBwcnVuZWRGc3RfZ3ckbnVsbC5Gc3QuOTVxW3BdPC1mc3RhdHMkdTk1WzFdCiAgICAKICAgICNDYWxjdWxhdGUgcC12YWx1ZXMKICAgIHB2YWw8LWZzdHdpblssIHAgOj0gY2FsY3AoZnN0LCBudWxsJHgpLCBieSA9IC4oQ0hST00sIG1pZFBvcyldCiAgICAKICAgICNjb21iaW5lZCB0aGUgZGF0YXNldHMKICAgIHBhaXI8LXBhc3RlMChjb21iW3AsMV0sIl8iLGNvbWJbcCwyXSkKICAgIGZzdHdpblssIHBvcCA6PSBwYWlyIF0KICAgIHdyaXRlLmNzdihmc3R3aW4sIHBhc3RlMCgiLi4vT3V0cHV0L0ZzdC9mc3Rfc2l0ZXNodWZmbGUucGFpcndpc2VfIiwgcGFpciwiLmNzdiIpKQp9Cgp3cml0ZS5jc3YocHJ1bmVkRnN0X2d3LCAiLi4vT3V0cHV0L0ZzdC9mc3Rfc2l0ZXNodWZmbGVfcHdzX3N1bW1hcnkuY3N2IikKCmRhdGE8LWRhdGEuZnJhbWUoKQpmb3IoaSBpbiAxOiBucm93KGNvbWIpKXsKICAgIHBhaXI8LXBhc3RlMChjb21iW2ksMV0sIl8iLGNvbWJbaSwyXSkKICAgIGRmPC1mcmVhZChwYXN0ZTAoIi4uL091dHB1dC9Gc3QvZnN0X3NpdGVzaHVmZmxlLnBhaXJ3aXNlXyIsIHBhaXIsIi5jc3YiKSkKICAgIGRmPC1kZlshaXMubmEoZnN0KSAmIG1pZFBvcyA+IDAsIF0KICAgIGRmWyxjaDo9IGFzLmludGVnZXIoZ3N1YigiY2hyIiwnJywgQ0hST00pKV0KICAgIHNldGtleShkZixDSFJPTSkKICAgIGRmPC1kZltjaHJtYXhbLCAuKENIUk9NID0gY2hyLCBzdGFydCldLCBdCiAgICBkZlsscG9zLmd3Oj0gbWlkUG9zK3N0YXJ0XQogICAgI3NldGtleShkZiwgY2gsIG1pZFBvcykKICAgIGRhdGE8LXJiaW5kKGRhdGEsIGRmKQp9Cgp3cml0ZS5jc3YoZGF0YSwgZmlsZSA9IGd6ZmlsZSgnLi4vT3V0cHV0L0ZzdC9mc3Rfc2l0ZXNodWZmbGUuYW5nc2QuUFdTLmNzdi5neicpLCByb3cubmFtZXMgPSBGQUxTRSkKYGBgCgoKIyMgUGxvdCB0aGUgcmVzdWx0cyAgICAgIApgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKZGF0YTwtZnJlYWQoJy4uL091dHB1dC9Gc3QvZnN0X3NpdGVzaHVmZmxlLmFuZ3NkLlBXUy5jc3YuZ3onKQoKI3BvcCBhcyBmYWN0b3IgCmRhdGFbLCBwb3AgOj0gZmFjdG9yKHBvcCwgbGV2ZWxzID0gYygiUFdTOTFfUFdTOTYiLCJQV1M5MV9QV1MwNyIsIlBXUzkxX1BXUzE3IiwiUFdTOTZfUFdTMDciLCJQV1M5Nl9QV1MxNyIsIlBXUzA3X1BXUzE3IikpXQoKIyBwbG90IHAtdmFsdWUgdnMuIHBvc2l0aW9uCnR3b19jb2xzPC1yZXAoYygic3RlZWxibHVlIiwibGlnaHRibHVlIiksIHRpbWVzPTEzKQptaW5sb2NpIDwtIDEwICMgbWluaW11bSBudW1iZXIgb2YgbG9jaSBwZXIgd2luZG93IHRvIGNvbnNpZGVyCgpnZ3Bsb3QoZGF0YVtubG9jaSA+PSBtaW5sb2NpLCBdLCBhZXMocG9zLmd3LCAtbG9nMTAocCksIGNvbG9yID0gZmFjdG9yKGNoKSkpICsgCiAgICBnZW9tX3BvaW50KHNpemUgPSAwLjIsIGFscGhhID0gMC41KSArCiAgICBmYWNldF93cmFwKH5wb3AsIG5jb2wgPSAxKSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gdHdvX2NvbHMsIGd1aWRlPSdub25lJykgKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gLWxvZzEwKDAuMDUpLCBsaW5ldHlwZSA9ICdkYXNoZWQnLCBjb2xvciA9ICdncmV5JykrCiAgICB0aGVtZV9idygpKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCkpKwogICAgeGxhYigiR2Vub21lIikKZ2dzYXZlKCIuLi9PdXRwdXQvRnN0L2ZzdC5zaXRlc2h1ZmZsZS5wX3ZzX3Bvcy5QV1MucG5nIiwgd2lkdGggPSA3LjUsIGhlaWdodCA9IDcuNSxkcGkgPSAzMDApCmBgYAohW10oLi4vT3V0cHV0L0ZzdC9mc3Quc2l0ZXNodWZmbGUucF92c19wb3MuUFdTLnBuZykKCi0gTnVtYmVyIG9mIGxvY2kgcGVyIHdpbmRvdyB2cy4gRnN0IHAtdmFsdWVzCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIHBsb3QgcC12YWx1ZSB2cy4gbmxvY2kgdG8gY2hlY2sgaWYgYW55IGJpYXNlcyBleGlzdApnZ3Bsb3QoZGF0YSwgYWVzKG5sb2NpLCAtbG9nMTAocCksIGNvbG9yID0gcG9wKSkgKyAKICAgIGdlb21fcG9pbnQoc2l6ZSA9IDAuNiwgYWxwaGEgPSAwLjUpICsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IC1sb2cxMCgwLjA1KSwgbGluZXR5cGUgPSAnZGFzaGVkJywgY29sb3IgPSAnZ3JleScpICsgCiAgICBzY2FsZV94X2xvZzEwKCkrdGhlbWVfYncoKSt0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpKwogICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDMsIGFscGhhPTEpKSkKZ2dzYXZlKCIuLi9PdXRwdXQvRnN0L2ZzdC5zaXRlc2h1ZmZsZS5wX3ZzX25sb2NpLlBXUy5wbmciLCB3aWR0aCA9IDgsIGhlaWdodCA9NCxkcGkgPSAzMDApCmBgYAoKIVtdKC4uL091dHB1dC9Gc3QvZnN0LnNpdGVzaHVmZmxlLnBfdnNfbmxvY2kuUFdTLnBuZyl7d2lkdGg9NzAlfQoKIyMgU2lnbmlmaWNhbnQgb3V0bGllciByZWdpb25zICAKCiMjIyBwLXZhbHVlIDwgMC4wNQoKYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpvdXRsaWVyczwtZGF0YVtwIDwgMC4wNSwgXQp3cml0ZS5jc3Yob3V0bGllcnMsICIuLi9PdXRwdXQvRnN0L0ZzdF9udWxsc2h1ZmZsaW5nX291dGxpZXJzX1BXUy5jc3YiKQoKY291bnRzPC1kYXRhLnRhYmxlKHRhYmxlKG91dGxpZXJzJHBvcCkpCmdncGxvdChjb3VudHMsIGFlcyh4PVYxLCB5PU4pKSsKICAgIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgZmlsbD1jb2xzWzRdKSsKICAgIHhsYWIoJycpK3lsYWIoJycpKwogICAgdGhlbWVfY2xhc3NpYygpKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpKQpnZ3NhdmUoIi4uL091dHB1dC9Gc3QvRnN0X291dGxpZXJzX2J5Q29tcGFyaXNvbi5wbmciLCB3aWR0aCA9IDQsIGhlaWdodCA9IDMsIGRwaT0zMDAgKQoKCmNvdW50cyRWMTwtZmFjdG9yKGNvdW50cyRWMSwgbGV2ZWxzPWMoIlBXUzk2X1BXUzA3IiwiUFdTMDdfUFdTMTciLCJQV1M5MV9QV1M5NiIsICJQV1M5MV9QV1MwNyIsICJQV1M5MV9QV1MxNyIsIlBXUzk2X1BXUzE3IikpCmdncGxvdChjb3VudHMsIGFlcyh4PVYxLCB5PU4sIGZpbGw9VjEpKSsKICAgIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IikrCiAgICBzY2FsZV9maWxsX21hbnVhbChuYW1lID0gIlYiLHZhbHVlcyA9IGRpdjIpKwogICAgeGxhYignJykreWxhYignTnVtYmVyIG9mIHJlZ2lvbnMgd2l0aCBQPDAuMDUnKSsKICAgIHRoZW1lX2NsYXNzaWMoKStnZ3RpdGxlKCJGc3QgKHNodWZmbGUpIikrCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3Q9MSksIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKZ2dzYXZlKCIuLi9PdXRwdXQvRnN0L0ZzdF9vdXRsaWVyc19ieUNvbXBhcmlzb25fb3JkZXJlZC5wbmciLCB3aWR0aCA9IDQsIGhlaWdodCA9IDMsIGRwaT0zMDAgKQoKCgojb3V0bGllcnM8LXJlYWQuY3N2KCIuLi9PdXRwdXQvRnN0L0ZzdF9udWxsc2h1ZmZsaW5nX291dGxpZXJzX1BXUy5jc3YiLCByb3cubmFtZXMgPSAxKQprbml0cjo6a2FibGUob3V0bGllcnNbLGMoMiwzLDQsNSw2LDcsOCldLCBjYXB0aW9uPSJPdXRsaWVyIHJlZ2lvbnMiKQoKI091dGxpZXIgcmVnaW9ucwojQ0hST00JbWlkUG9zCWZzdAlubG9jaQlwCXBvcAljaAojY2hyMjUJODI1MDAwCTAuMTIxMDk5NwkxMzgJMC4wMDM5OTYJUFdTOTZfUFdTMDcJMjUKI2NocjI1CTgzNTAwMAkwLjA4MTg4MDIJMjc5CTAuMDIwOTc5CVBXUzk2X1BXUzA3CTI1CiNjaHIyNQk4NDUwMDAJMC4wNzIxOTI2CTMxMQkwLjAzMzk2NglQV1M5Nl9QV1MwNwkyNQojY2hyMjUJODA1MDAwCTAuMTI0MjY1MgkxNjYJMC4wMDI5OTcJUFdTOTZfUFdTMDcJMjUKI2NocjI1CTgxNTAwMAkwLjEzNzcyMTgJMTU1CTAuMDAyOTk3CVBXUzk2X1BXUzA3CTI1CiNjaHIxOQkxMzc1MDAwCTAuMTI1MTYwMgk0MgkwLjAwMzk5NglQV1MwN19QV1MxNwkxOQoKYGBgCiFbXSguLi9PdXRwdXQvRnN0L0ZzdF9vdXRsaWVyc19ieUNvbXBhcmlzb24ucG5nKSAKCgojIyMgVG9wIDElIG91dGxpZXJzICYgUDwgMC4yCiogcmVsYXhpbmcgdGhlIGN1dG9mZgpgYGB7cn0KI2RhdGE8LWZyZWFkKCcuLi9PdXRwdXQvRnN0L2ZzdF9zaXRlc2h1ZmZsZS5hbmdzZC5QV1MuY3N2Lmd6JykKZGF0PC1kYXRhW29yZGVyKHApLF0KdG9wMTwtZGF0WzE6KG5yb3coZGF0KSowLjAxKSxdCnRvcDE8LXRvcDFbcDwwLjIsXQoKY291bnRzMjwtZGF0YS50YWJsZSh0YWJsZSh0b3AxJHBvcCkpCmdncGxvdChjb3VudHMyLCBhZXMoeD1WMSwgeT1OKSkrCiAgICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIGZpbGw9Y29sc1s0XSkrCiAgICB4bGFiKCcnKSt5bGFiKCcnKSsKICAgIHRoZW1lX2NsYXNzaWMoKSsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LCBoanVzdD0xKSkKZ2dzYXZlKCIuLi9PdXRwdXQvRnN0L0ZzdF9vdXRsaWVyc19ieUNvbXBhcmlzb25fdG9wMXBlcmNlbnQucG5nIiwgd2lkdGggPSA0LCBoZWlnaHQgPSAzLCBkcGk9MzAwICkKCgoKCmtuaXRyOjprYWJsZSh0b3AxWyxjKDIsMyw0LDUsNiw3LDgpXSkKYGBgCiFbXSguLi9PdXRwdXQvRnN0L0ZzdF9vdXRsaWVyc19ieUNvbXBhcmlzb25fdG9wMXBlcmNlbnQucG5nKSAgCgohW10oLi4vT3V0cHV0L0ZzdC9wY2FuZ3NkX3NjYW5faGlnaFBzaXRlcy5wbmcpICAKKiAqKk5PIG92ZXJsYXBwaW5nIHJlZ2lvbnMgZnJvbSBQQ0FuZ3NkIHNlbGVjdGlvbiBzY2FuKioKCgoKCgoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCmBgYAoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCmBgYAo=